[
https://issues.apache.org/jira/browse/WICKET-7033?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17710919#comment-17710919
]
ASF GitHub Bot commented on WICKET-7033:
----------------------------------------
martin-g commented on code in PR #571:
URL: https://github.com/apache/wicket/pull/571#discussion_r1162678493
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java:
##########
@@ -0,0 +1,206 @@
+/*
+ * 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.commons.fileupload.FileUploadBase;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.wicket.WicketRuntimeException;
+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}
Review Comment:
s/IUploadsFileManager/IFileUploadManager/ ?
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java:
##########
@@ -0,0 +1,206 @@
+/*
+ * 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.commons.fileupload.FileUploadBase;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.wicket.WicketRuntimeException;
+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 (FileUploadException e)
+ {
+ if (e instanceof
FileUploadBase.FileSizeLimitExceededException || e instanceof
FileUploadBase.SizeLimitExceededException)
+ {
+ resourceResponse.setError(413, "File size
exceeded!");
+ return resourceResponse;
+ }
+ throw new WicketRuntimeException(e);
+ }
+ 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());
Review Comment:
We should probably use some generic error message instead.
Use the real exception message only if `LOGGER.isDebugEnabled() == true`
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java:
##########
@@ -0,0 +1,206 @@
+/*
+ * 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.commons.fileupload.FileUploadBase;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.wicket.WicketRuntimeException;
+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";
Review Comment:
```suggestion
public static final String PARAM_NAME = "WICKET-FILE-UPLOAD";
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java:
##########
@@ -0,0 +1,124 @@
+/*
+ * 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;
Review Comment:
```suggestion
private static FileUploadResourceReference instance;
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
Review Comment:
The `file` might be `null`
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
Review Comment:
I am still not sure what this identifier is. I think it deserves some javadoc
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java:
##########
@@ -0,0 +1,206 @@
+/*
+ * 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.commons.fileupload.FileUploadBase;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.wicket.WicketRuntimeException;
+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");
Review Comment:
Extract a constant for `"uploadId"` with some javadoc about what is its
purpose
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
Review Comment:
final ?
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
Review Comment:
```suggestion
protected abstract List<UploadInfo> getFileUploadInfos();
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileInfos;
+
+ public FileUploadToResourceField(String id) {
+ super(id);
+ setOutputMarkupId(true);
+ setMarkupId("WRFUF" + getUserId() + System.currentTimeMillis());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getIdentifier()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileInfos()
+ {
+ return fileInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ boolean success =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("success").toBoolean(false);
+ if (success) {
+ String filesIfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("filesInfo").toString();
+ fileInfos = UploadInfo.fromJson(filesIfo);
+ onUploadSuccess(target, getFileInfos());
+ if (deleteFilesAfterUpload())
+ {
+ for (UploadInfo uploadInfo : fileInfos)
+ {
+ fileManager().deleteFile(getMarkupId(),
uploadInfo.clientFileName);
+ }
+ }
+ }
+ else
+ {
+ String errorInfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("errorMessage").toString(null);
+ if (UPLOAD_CANCELED.equals(errorInfo))
+ {
+ onUploadCanceled(target);
+ } else {
+ onUploadFailure(target, errorInfo);
+ }
+ }
+ }
+ };
+ add(ajaxBehavior);
+ }
+
+ /**
+ * @return determines whether the file is deleted after upload has happened
+ * or not.
+ */
+ protected boolean deleteFilesAfterUpload()
+ {
+ return true;
+ }
+
+
+ /**
+ * @return determines whether the created files are deleted on remove
+ */
+ protected boolean clearFilesOnRemove()
+ {
+ return true;
+ }
+
+ private List<UploadInfo> getFileInfos()
+ {
+ return (List<UploadInfo>)getDefaultModel().getObject();
+ }
+
+ @Override
+ public FileUpload getFileUpload() {
+ throw new
UnsupportedOperationException("SingleFileUploadToResourceField does not support
working with FileUpload");
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+ // we clean any client side mess if component is removed via "partial"
page replacement
+ AjaxUtils.executeIfAjaxOrWebSockets(target ->
target.appendJavaScript("delete window." + getMarkupId() + ";"));
Review Comment:
Do not pollute the `window` object.
I think we have `Wicket.Timer` that could be used instead.
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileInfos;
+
+ public FileUploadToResourceField(String id) {
+ super(id);
+ setOutputMarkupId(true);
+ setMarkupId("WRFUF" + getUserId() + System.currentTimeMillis());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getIdentifier()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileInfos()
+ {
+ return fileInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ boolean success =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("success").toBoolean(false);
+ if (success) {
+ String filesIfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("filesInfo").toString();
+ fileInfos = UploadInfo.fromJson(filesIfo);
+ onUploadSuccess(target, getFileInfos());
+ if (deleteFilesAfterUpload())
+ {
+ for (UploadInfo uploadInfo : fileInfos)
+ {
+ fileManager().deleteFile(getMarkupId(),
uploadInfo.clientFileName);
+ }
+ }
+ }
+ else
+ {
+ String errorInfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("errorMessage").toString(null);
+ if (UPLOAD_CANCELED.equals(errorInfo))
+ {
+ onUploadCanceled(target);
+ } else {
+ onUploadFailure(target, errorInfo);
+ }
+ }
+ }
+ };
+ add(ajaxBehavior);
+ }
+
+ /**
+ * @return determines whether the file is deleted after upload has happened
+ * or not.
+ */
+ protected boolean deleteFilesAfterUpload()
+ {
+ return true;
+ }
+
+
+ /**
+ * @return determines whether the created files are deleted on remove
+ */
+ protected boolean clearFilesOnRemove()
+ {
+ return true;
+ }
+
+ private List<UploadInfo> getFileInfos()
+ {
+ return (List<UploadInfo>)getDefaultModel().getObject();
+ }
+
+ @Override
+ public FileUpload getFileUpload() {
+ throw new
UnsupportedOperationException("SingleFileUploadToResourceField does not support
working with FileUpload");
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+ // we clean any client side mess if component is removed via "partial"
page replacement
+ AjaxUtils.executeIfAjaxOrWebSockets(target ->
target.appendJavaScript("delete window." + getMarkupId() + ";"));
+ if (clearFilesOnRemove())
+ {
+ fileManager().deleteFiles(getMarkupId());
+ }
+ }
+
+ /**
+ * Override to do something on a successful upload. Mind that if {@link
#deleteFilesAfterUpload()} returns <code>true</code>
+ * then after this method is called the file will be deleted. Thus, it is
your responsibility to store the file somewhere
+ * in this method.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ * @param fileInfos The List<FileInfo
+ */
+ protected abstract void onUploadSuccess(AjaxRequestTarget target,
List<UploadInfo> fileInfos);
+
+
+ /**
+ * Override to do something on a non successful upload
+ *
+ * @param target The {@link AjaxRequestTarget}
+ * @param errorInfo The cause of the failure
+ */
+ protected void onUploadFailure(AjaxRequestTarget target, String errorInfo)
+ {
+ // nothing by default
+ }
+
+ /**
+ * Override to do something in case user canceled upload
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ protected void onUploadCanceled(AjaxRequestTarget target)
+ {
+ // nothing by default
+ }
+
+ /**
+ * @return a unique identifier for the user (session) doing the upload.
+ */
+ protected String getUserId()
+ {
+ return Session.get().getId() != null ? Session.get().getId() : "Annon";
Review Comment:
s/Annon/Anon/
But since we use Wicket Ajax behaviors is it possible at all to be anonymous
?
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js:
##########
@@ -0,0 +1,99 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientSideSuccessCallBack, clientSideCancelCallBack, connectionErrorCallBack)
+ {
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName;
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.connectionErrorCallBack = connectionErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("FILE-UPLOAD",this.input.files[index]);
+ }
+ // pass the input name to knw where to store files at server side.
+ formData.append("uploadId", this.inputName);
+ var self = this;
+ // we use jQuery to post the file to the resource (this.resourceUrl)
+ // and we keep a reference to the request in order to be able
+ // 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.clientSideSuccessCallBack();
Review Comment:
shouldn't this call be in the `else` clause ?
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileInfos;
+
+ public FileUploadToResourceField(String id) {
+ super(id);
+ setOutputMarkupId(true);
+ setMarkupId("WRFUF" + getUserId() + System.currentTimeMillis());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getIdentifier()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileInfos()
+ {
+ return fileInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ boolean success =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("success").toBoolean(false);
+ if (success) {
+ String filesIfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("filesInfo").toString();
+ fileInfos = UploadInfo.fromJson(filesIfo);
+ onUploadSuccess(target, getFileInfos());
+ if (deleteFilesAfterUpload())
+ {
+ for (UploadInfo uploadInfo : fileInfos)
+ {
+ fileManager().deleteFile(getMarkupId(),
uploadInfo.clientFileName);
+ }
+ }
+ }
+ else
+ {
+ String errorInfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("errorMessage").toString(null);
+ if (UPLOAD_CANCELED.equals(errorInfo))
+ {
+ onUploadCanceled(target);
+ } else {
+ onUploadFailure(target, errorInfo);
+ }
+ }
+ }
+ };
+ add(ajaxBehavior);
+ }
+
+ /**
+ * @return determines whether the file is deleted after upload has happened
+ * or not.
+ */
+ protected boolean deleteFilesAfterUpload()
+ {
+ return true;
+ }
+
+
+ /**
+ * @return determines whether the created files are deleted on remove
+ */
+ protected boolean clearFilesOnRemove()
+ {
+ return true;
+ }
+
+ private List<UploadInfo> getFileInfos()
+ {
+ return (List<UploadInfo>)getDefaultModel().getObject();
+ }
+
+ @Override
+ public FileUpload getFileUpload() {
+ throw new
UnsupportedOperationException("SingleFileUploadToResourceField does not support
working with FileUpload");
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+ // we clean any client side mess if component is removed via "partial"
page replacement
+ AjaxUtils.executeIfAjaxOrWebSockets(target ->
target.appendJavaScript("delete window." + getMarkupId() + ";"));
+ if (clearFilesOnRemove())
+ {
+ fileManager().deleteFiles(getMarkupId());
+ }
+ }
+
+ /**
+ * Override to do something on a successful upload. Mind that if {@link
#deleteFilesAfterUpload()} returns <code>true</code>
+ * then after this method is called the file will be deleted. Thus, it is
your responsibility to store the file somewhere
+ * in this method.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ * @param fileInfos The List<FileInfo
+ */
+ protected abstract void onUploadSuccess(AjaxRequestTarget target,
List<UploadInfo> fileInfos);
+
+
+ /**
+ * Override to do something on a non successful upload
+ *
+ * @param target The {@link AjaxRequestTarget}
+ * @param errorInfo The cause of the failure
+ */
+ protected void onUploadFailure(AjaxRequestTarget target, String errorInfo)
+ {
+ // nothing by default
+ }
+
+ /**
+ * Override to do something in case user canceled upload
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ protected void onUploadCanceled(AjaxRequestTarget target)
+ {
+ // nothing by default
+ }
+
+ /**
+ * @return a unique identifier for the user (session) doing the upload.
+ */
+ protected String getUserId()
+ {
+ return Session.get().getId() != null ? Session.get().getId() : "Annon";
+ }
+
+
+ @Override
+ public void renderHead(IHeaderResponse response)
+ {
+ CoreLibrariesContributor.contributeAjax(getApplication(), response);
+ response.render(JavaScriptHeaderItem.forReference(JS));
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("inputName", getMarkupId());
+ jsonObject.put("resourceUrl", urlFor(getFileUploadResourceReference(),
new PageParameters()).toString());
+ jsonObject.put("ajaxCallBackUrl", ajaxBehavior.getCallbackUrl());
+ response.render(OnDomReadyHeaderItem.forScript("window."
+ + getMarkupId() + " = new Wicket.FileUploadToResourceField("
+ + jsonObject + ","
+ + getClientSideSuccessCallBack() + "," +
getClientSideCancelCallBack() + ","
+ + getConnectionErrorCallBack() + ");"));
+ }
+
+ /**
+ * Override if you need to return a different instance of
FileUploadResourceReference
+ * @return FileUploadResourceReference
+ */
+ protected FileUploadResourceReference getFileUploadResourceReference()
+ {
+ return FileUploadResourceReference.getInstance();
+ }
+
+ /**
+ * @return The JavaScript expression starting the upload.
+ */
+ public String getTriggerUploadScript()
+ {
+ return "window." + getMarkupId() + ".upload();";
+ }
+
+ /**
+ * Starts the upload via an AJAX request.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ public void startUpload(IPartialPageRequestHandler target)
+ {
+ target.appendJavaScript(getTriggerUploadScript());
+ }
+
+ /**
+ * @return The JavaScript expression canceling the upload.
+ */
+ public String getTriggerCancelUploadScript()
+ {
+ return "window." + getMarkupId() + ".cancel();";
+ }
+ /**
+ * Cancels the upload via an AJAX request.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ public void cancelUpload(IPartialPageRequestHandler target)
+ {
+ target.appendJavaScript(getTriggerCancelUploadScript());
+ }
+
+ /**
+ * @return A JavaScript function to be executed on successful upload. This
is, besides the normal wicket
+ * AJAX request (see {@link #onUploadSuccess(AjaxRequestTarget, List)}).
+ */
+ protected String getClientSideSuccessCallBack()
Review Comment:
Are those clientside callbacks really needed ?
I don't quite like the Strings they return ...
##########
wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadApplication.java:
##########
@@ -55,9 +61,22 @@ protected void init()
// Ensure folder exists
uploadFolder.mkdirs();
+ uploadsFileManager = new FolderUploadsFileManager(uploadFolder);
+
+ mountResource("/uploads",
FileUploadResourceReference.createNewInstance(uploadsFileManager,
Bytes.megabytes(100)));
Review Comment:
100M is too big. We deploy the examples app at
https://examples9x.wicket.apache.org and this may consume out disks quickly.
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java:
##########
@@ -0,0 +1,124 @@
+/*
+ * 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;
+
+ /**
+ * This method assumes {@link #createNewInstance(IUploadsFileManager,
Bytes)} was called before
Review Comment:
Why not merged the two methods ?
`getInstance()` could do what `#createNewInstance()` does.
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
Review Comment:
```
This field does not require a {@link
org.apache.wicket.markup.html.form.Form}!
The upload of the file id done via the {@link
#startUpload(IPartialPageRequestHandler)} method.
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
Review Comment:
log it as debug ?!
##########
wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.html:
##########
@@ -0,0 +1,39 @@
+<html xmlns:wicket="http://wicket.apache.org">
+<head>
+ <title>Wicket Examples - upload</title>
+ <style>
+ legend { border: 1px solid #e9601a; background-color: #bbb;
color: #fff; padding: 4px;}
+ fieldset { border: 1px solid #e9601a; padding: 10px;
margin-top: 10px;}
+ </style>
+</head>
+<body>
+ <wicket:extend>
+
+ <p>Wicket can upload to a <strong>mounted to a resource.</strong></p>
+ <p>This upload is done via jQuery and does not block wicket AJAX</p>
Review Comment:
```suggestion
<p>This upload is done via jQuery and does not block Wicket AJAX</p>
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js:
##########
@@ -0,0 +1,99 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientSideSuccessCallBack, clientSideCancelCallBack, connectionErrorCallBack)
+ {
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName;
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.connectionErrorCallBack = connectionErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("FILE-UPLOAD",this.input.files[index]);
+ }
+ // pass the input name to knw where to store files at server side.
Review Comment:
```suggestion
// pass the input name to know where to store files at server side.
```
##########
wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/progressbar.js:
##########
@@ -117,8 +135,14 @@
this.iframe = null;
if (progressPercent === '100') {
- Wicket.$(this.statusid).setAttribute('hidden',
'');
- Wicket.$(this.barid).setAttribute('hidden', '');
+ var $statusId = Wicket.$(this.statusid);
+ if ($statusId != null) {
+ $statusId.setAttribute('hidden', '');
Review Comment:
Why use `hidden` attribute ?
Can we use Wicket.DOM's `hide()` and `show()` instead ?
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileInfos;
+
+ public FileUploadToResourceField(String id) {
+ super(id);
+ setOutputMarkupId(true);
+ setMarkupId("WRFUF" + getUserId() + System.currentTimeMillis());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getIdentifier()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileInfos()
+ {
+ return fileInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ boolean success =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("success").toBoolean(false);
Review Comment:
cache the value of `RequestCycle.get().getRequest().getRequestParameters()`
and reuse it
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileInfos;
+
+ public FileUploadToResourceField(String id) {
+ super(id);
+ setOutputMarkupId(true);
+ setMarkupId("WRFUF" + getUserId() + System.currentTimeMillis());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getIdentifier()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileInfos()
+ {
+ return fileInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ boolean success =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("success").toBoolean(false);
+ if (success) {
+ String filesIfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("filesInfo").toString();
+ fileInfos = UploadInfo.fromJson(filesIfo);
+ onUploadSuccess(target, getFileInfos());
+ if (deleteFilesAfterUpload())
+ {
+ for (UploadInfo uploadInfo : fileInfos)
+ {
+ fileManager().deleteFile(getMarkupId(),
uploadInfo.clientFileName);
+ }
+ }
+ }
+ else
+ {
+ String errorInfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("errorMessage").toString(null);
+ if (UPLOAD_CANCELED.equals(errorInfo))
+ {
+ onUploadCanceled(target);
+ } else {
+ onUploadFailure(target, errorInfo);
+ }
+ }
+ }
+ };
+ add(ajaxBehavior);
+ }
+
+ /**
+ * @return determines whether the file is deleted after upload has happened
+ * or not.
+ */
+ protected boolean deleteFilesAfterUpload()
+ {
+ return true;
+ }
+
+
+ /**
+ * @return determines whether the created files are deleted on remove
+ */
+ protected boolean clearFilesOnRemove()
+ {
+ return true;
+ }
+
+ private List<UploadInfo> getFileInfos()
+ {
+ return (List<UploadInfo>)getDefaultModel().getObject();
+ }
+
+ @Override
+ public FileUpload getFileUpload() {
+ throw new
UnsupportedOperationException("SingleFileUploadToResourceField does not support
working with FileUpload");
Review Comment:
SingleFileUploadToResourceField - Single ?!
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java:
##########
@@ -0,0 +1,414 @@
+/*
+ * 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 java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}, and field by itself
+ * does to upload of the file via the {@link
#startUpload(IPartialPageRequestHandler)} method. See wicket examples.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload.
+ */
+ public byte[] get()
+ {
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileInfos();
+ for (UploadInfo uploadInfo : fileInfos){
+ uploadInfo.setFile(fileManager().getFile(getIdentifier(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ protected abstract String getIdentifier();
+ protected abstract List<UploadInfo> getFileInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileInfos;
+
+ public FileUploadToResourceField(String id) {
+ super(id);
+ setOutputMarkupId(true);
+ setMarkupId("WRFUF" + getUserId() + System.currentTimeMillis());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getIdentifier()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileInfos()
+ {
+ return fileInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ boolean success =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("success").toBoolean(false);
+ if (success) {
+ String filesIfo =
RequestCycle.get().getRequest().getRequestParameters().getParameterValue("filesInfo").toString();
+ fileInfos = UploadInfo.fromJson(filesIfo);
+ onUploadSuccess(target, getFileInfos());
+ if (deleteFilesAfterUpload())
+ {
+ for (UploadInfo uploadInfo : fileInfos)
+ {
+ fileManager().deleteFile(getMarkupId(),
uploadInfo.clientFileName);
Review Comment:
This looks scary!
It seems I can provide specially crafted JSON with `filesInfo` and delete
files on the server ?!
##########
wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.html:
##########
@@ -0,0 +1,39 @@
+<html xmlns:wicket="http://wicket.apache.org">
+<head>
+ <title>Wicket Examples - upload</title>
+ <style>
+ legend { border: 1px solid #e9601a; background-color: #bbb;
color: #fff; padding: 4px;}
+ fieldset { border: 1px solid #e9601a; padding: 10px;
margin-top: 10px;}
+ </style>
+</head>
+<body>
+ <wicket:extend>
+
+ <p>Wicket can upload to a <strong>mounted to a resource.</strong></p>
Review Comment:
```suggestion
<p>Wicket can upload to a <strong>mounted resource.</strong></p>
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FolderUploadsFileManager.java:
##########
@@ -0,0 +1,102 @@
+/*
+ * 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.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.util.file.File;
+import org.apache.wicket.util.io.IOUtils;
+import org.apache.wicket.util.lang.Args;
+
+public class FolderUploadsFileManager implements IUploadsFileManager
Review Comment:
javadoc
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js:
##########
@@ -0,0 +1,99 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientSideSuccessCallBack, clientSideCancelCallBack, connectionErrorCallBack)
+ {
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName;
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.connectionErrorCallBack = connectionErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("FILE-UPLOAD",this.input.files[index]);
+ }
+ // pass the input name to knw where to store files at server side.
+ formData.append("uploadId", this.inputName);
+ var self = this;
+ // we use jQuery to post the file to the resource (this.resourceUrl)
+ // and we keep a reference to the request in order to be able
+ // 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.clientSideSuccessCallBack();
+ if (res.error) {
+ var ep = {'success': false, 'errorMessage':
res.errorMessage};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack(res);
+ } else {
+ var ep = {'success': true, 'filesInfo':
JSON.stringify(res)};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ }
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ if (textStatus === "abort") {
+ // user aborted the upload.
+ self.clientSideCancelCallBack();
+ var ep = {'success': false, 'errorMessage':
'upload.canceled'};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ } else if (textStatus === "error"){
+ var ep = {'success': false, 'errorMessage': errorThrown};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack();
+ } else if (textStatus === "parsererror"){
+ // this error will only happen is generated JSON at server
side is faulty
+ var data = jqXHR.responseText;
+ Wicket.Log.log(data);
+ }
+ }
+ });
+ }
+
+ // cancel the upload
+ Wicket.FileUploadToResourceField.prototype.cancel = function () {
+ // we have a reference to the request we can cancel it.
+ if (this.xhr) {
+ this.xhr.abort();
+ Wicket.Log.log("upload canceled!");
Review Comment:
```suggestion
Wicket.Log.log("the upload has been canceled!");
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js:
##########
@@ -0,0 +1,99 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientSideSuccessCallBack, clientSideCancelCallBack, connectionErrorCallBack)
+ {
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName;
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.connectionErrorCallBack = connectionErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("FILE-UPLOAD",this.input.files[index]);
+ }
+ // pass the input name to knw where to store files at server side.
+ formData.append("uploadId", this.inputName);
+ var self = this;
+ // we use jQuery to post the file to the resource (this.resourceUrl)
+ // and we keep a reference to the request in order to be able
+ // 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.clientSideSuccessCallBack();
+ if (res.error) {
+ var ep = {'success': false, 'errorMessage':
res.errorMessage};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack(res);
+ } else {
+ var ep = {'success': true, 'filesInfo':
JSON.stringify(res)};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ }
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ if (textStatus === "abort") {
+ // user aborted the upload.
+ self.clientSideCancelCallBack();
+ var ep = {'success': false, 'errorMessage':
'upload.canceled'};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ } else if (textStatus === "error"){
+ var ep = {'success': false, 'errorMessage': errorThrown};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack();
+ } else if (textStatus === "parsererror"){
+ // this error will only happen is generated JSON at server
side is faulty
+ var data = jqXHR.responseText;
+ Wicket.Log.log(data);
+ }
+ }
+ });
+ }
+
+ // cancel the upload
+ Wicket.FileUploadToResourceField.prototype.cancel = function () {
+ // we have a reference to the request we can cancel it.
+ if (this.xhr) {
+ this.xhr.abort();
+ Wicket.Log.log("upload canceled!");
+ delete (this.xhr);
+ } else {
+ Wicket.Log.log("Too late to cancel: upload already finished.");
Review Comment:
```suggestion
Wicket.Log.log("Too late to cancel: the upload has already
finished.");
```
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js:
##########
@@ -0,0 +1,99 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientSideSuccessCallBack, clientSideCancelCallBack, connectionErrorCallBack)
+ {
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName;
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.connectionErrorCallBack = connectionErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("FILE-UPLOAD",this.input.files[index]);
+ }
+ // pass the input name to knw where to store files at server side.
+ formData.append("uploadId", this.inputName);
+ var self = this;
+ // we use jQuery to post the file to the resource (this.resourceUrl)
+ // and we keep a reference to the request in order to be able
+ // 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.clientSideSuccessCallBack();
+ if (res.error) {
+ var ep = {'success': false, 'errorMessage':
res.errorMessage};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack(res);
+ } else {
+ var ep = {'success': true, 'filesInfo':
JSON.stringify(res)};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ }
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ if (textStatus === "abort") {
+ // user aborted the upload.
+ self.clientSideCancelCallBack();
+ var ep = {'success': false, 'errorMessage':
'upload.canceled'};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ } else if (textStatus === "error"){
+ var ep = {'success': false, 'errorMessage': errorThrown};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack();
+ } else if (textStatus === "parsererror"){
+ // this error will only happen is generated JSON at server
side is faulty
+ var data = jqXHR.responseText;
+ Wicket.Log.log(data);
+ }
+ }
+ });
+ }
+
+ // cancel the upload
+ Wicket.FileUploadToResourceField.prototype.cancel = function () {
+ // we have a reference to the request we can cancel it.
+ if (this.xhr) {
+ this.xhr.abort();
+ Wicket.Log.log("upload canceled!");
+ delete (this.xhr);
+ } else {
+ Wicket.Log.log("Too late to cancel: upload already finished.");
+ }
Review Comment:
For easier debugging I'd suggest to use ` this.inputName ` in the log
messages above.
##########
wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js:
##########
@@ -0,0 +1,99 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientSideSuccessCallBack, clientSideCancelCallBack, connectionErrorCallBack)
+ {
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName;
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.connectionErrorCallBack = connectionErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("FILE-UPLOAD",this.input.files[index]);
+ }
+ // pass the input name to knw where to store files at server side.
+ formData.append("uploadId", this.inputName);
+ var self = this;
+ // we use jQuery to post the file to the resource (this.resourceUrl)
+ // and we keep a reference to the request in order to be able
+ // 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.clientSideSuccessCallBack();
+ if (res.error) {
+ var ep = {'success': false, 'errorMessage':
res.errorMessage};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ self.connectionErrorCallBack(res);
Review Comment:
The Java method that provides the impl of `connectionErrorCallBack` should
be documented that the function accepts `res` as argument.
##########
wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/UploadProgressBar.java:
##########
@@ -112,14 +112,38 @@ public void destroy(final Application application)
private static final long serialVersionUID = 1L;
- private final Form<?> form;
+ private Form<?> form;
private MarkupContainer statusDiv;
private MarkupContainer barDiv;
private final FileUploadField uploadField;
+ /**
+ * Constructor that will display the upload progress bar for every
submit of the given form.
+ *
+ * @param id
+ * component id (not null)
+ * @param uploadField
+ * the file upload field to check for a file upload, or null
to display the upload
+ * field for every submit of the given form
+ */
+ public UploadProgressBar(final String id, final FileUploadField
uploadField)
+ {
+ super(id);
Review Comment:
You can call `this(id, null, Args.nonNull(uploadField, "uploadField"))`
And move the non-null Form from
https://github.com/apache/wicket/pull/571/files#diff-f75b5636ac8b2157552b9755243a10c168527c2132bd8ce61393386a49482047R183
to
https://github.com/apache/wicket/pull/571/files#diff-f75b5636ac8b2157552b9755243a10c168527c2132bd8ce61393386a49482047R157
> add support to uploading to a resource
> --------------------------------------
>
> Key: WICKET-7033
> URL: https://issues.apache.org/jira/browse/WICKET-7033
> Project: Wicket
> Issue Type: New Feature
> Components: wicket
> Reporter: Ernesto Reinaldo Barreiro
> Assignee: Ernesto Reinaldo Barreiro
> Priority: Major
> Fix For: 10.0.0, 9.14.0
>
>
> Add support for the following:
> * Upload to a resource in an asynchronous non page blocking request
> * Add an optional way to block the user from leaving the page while the
> upload is happening
> * Ways to cancel the upload
> * Adapt the upload progress bar to work with this new "component" and improve
> its code as in some corner cases it is producing client side errors (I
> created an issue for that some time ago).
> * Maybe useful too: create a web socket based progress bar, as the upload
> progress bar now works pulling the server every second.
> * Also to add an example to wicket-examples that uses a smart JS uploader,
> like in the blog
> (https://github.com/martin-g/blogs/blob/master/file-upload/). This way you
> will verify that the new APIs are easily extendable.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)