/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.server.projects.war.components; import java.io.BufferedInputStream; import java.io.File; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.form.upload.FileUpload; import org.apache.wicket.markup.html.form.upload.FileUploadField; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.Model; import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.util.lang.Bytes; import org.apache.wicket.util.string.StringValue; import org.apache.wicket.util.upload.FileUploadBase.SizeLimitExceededException; import org.apache.wicket.util.upload.FileUploadException; import org.apache.wicket.validation.IValidatable; import org.apache.wicket.validation.IValidator; import org.apache.wicket.validation.ValidationError; import org.apache.wicket.validation.validator.PatternValidator; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import eu.esdihumboldt.hale.server.projects.ProjectScavenger; import eu.esdihumboldt.hale.server.projects.war.pages.ProjectsPage; import eu.esdihumboldt.hale.server.webapp.components.FieldMessage; import eu.esdihumboldt.hale.server.webapp.components.FieldValidatingBehavior; import eu.esdihumboldt.util.io.IOUtils; import eu.esdihumboldt.util.scavenger.ScavengerException; /** * Upload form for new projects. * * @author Simon Templer */ public class UploadForm extends Form<Void> { private static final long serialVersionUID = -8077630706189091706L; private static final ALogger log = ALoggerFactory.getLogger(UploadForm.class); private final FileUploadField file; private final TextField<String> identifier; private Set<String> allowedContentTypes = null; private String customTypeErrorMessage = null; @SpringBean private ProjectScavenger projects; /** * @see Form#Form(String) */ public UploadForm(String id) { super(id); // multipart always needed for uploads setMultiPart(true); // input field for identifier text identifier = new TextField<String>("identifier", new Model<String>()); // pattern validator identifier.add(new PatternValidator("[A-Za-z0-9 _\\-]+")); // validator that checks if the project name is already taken identifier.add(new IValidator<String>() { private static final long serialVersionUID = 275885544279441469L; @Override public void validate(IValidatable<String> validatable) { String name = validatable.getValue(); for (String project : projects.getResources()) { // ignore case to avoid confusion if (name.equalsIgnoreCase(project)) { validatable.error(new ValidationError() .setMessage("Identifier already in use")); break; } } } }); FieldMessage identifierMessage = new FieldMessage("identifierMessage", new Model<String>( "Unique identifier for the project"), identifier); identifier.add(new FieldValidatingBehavior("onblur", identifierMessage)); identifier.setOutputMarkupId(true); identifier.setRequired(true); // identifier.add(new DefaultFocus()); XXX not working well with ajax add(identifier); add(identifierMessage); // Add one file input field add(file = new FileUploadField("file")); add(new FeedbackPanel("feedback")); addAllowedContentType("application/zip"); addAllowedContentType("application/x-zip"); addAllowedContentType("application/x-zip-compressed"); addAllowedContentType("application/octet-stream"); // setCustomTypeErrorMessage("Only ZIP archives are supported for upload"); setMaxSize(Bytes.megabytes(20)); } /** * Add an allowed content type. If none is added, any content type is * allowed. * * @param contentType the content type to add */ public void addAllowedContentType(String contentType) { if (allowedContentTypes == null) { allowedContentTypes = new HashSet<String>(); } allowedContentTypes.add(contentType); } /** * Check if the given content type is allowed for upload * * @param contentType the content type * * @return if the upload shall be allowed */ protected boolean checkContentType(String contentType) { if (allowedContentTypes == null) { return true; } else { return allowedContentTypes.contains(contentType); } } /** * @see Form#onSubmit() */ @Override protected void onSubmit() { final String project = identifier.getModel().getObject(); try { final FileUpload upload = file.getFileUpload(); if (upload != null) { File dir = projects.reserveResourceId(project); // File target = new File(dir, upload.getClientFileName()); String type = upload.getContentType(); if (checkContentType(type)) { // IOUtils.copy(upload.getInputStream(), new FileOutputStream(target)); // try extracting the archive IOUtils.extract(dir, new BufferedInputStream(upload.getInputStream())); // trigger scan after upload projects.triggerScan(); info("Successfully uploaded project"); onUploadSuccess(); } else { projects.releaseResourceId(project); error(getTypeErrorMessage(type)); } } else { warn("Please provide a file for upload"); } } catch (ScavengerException e) { error(e.getMessage()); } catch (Exception e) { projects.releaseResourceId(project); log.error("Error while uploading file", e); error("Error saving the file"); } } /** * Called after a successful upload. */ protected void onUploadSuccess() { setResponsePage(ProjectsPage.class); } /** * Get the error message if the upload of the given type is not supported * * @param type the content type * * @return the error message */ protected String getTypeErrorMessage(String type) { if (customTypeErrorMessage != null) { return customTypeErrorMessage; } else { return "Files of type " + type + " are not supported."; } } /** * @see Form#onFileUploadException(FileUploadException, Map) */ @Override protected void onFileUploadException(FileUploadException e, Map<String, Object> model) { if (e instanceof SizeLimitExceededException) { final String msg = "Only files up to " + bytesToString(getMaxSize(), Locale.US) + " can be uploaded."; error(msg); } else { final String msg = "Error uploading the file: " + e.getLocalizedMessage(); error(msg); log.warn(msg, e); } } /** * @param customTypeErrorMessage the customTypeErrorMessage to set */ public void setCustomTypeErrorMessage(String customTypeErrorMessage) { this.customTypeErrorMessage = customTypeErrorMessage; } /** * Convert {@link Bytes} to a string, produces a prettier output than * {@link Bytes#toString(Locale)} * * @param bytes the bytes * @param locale the locale * * @return the converted string */ public static String bytesToString(Bytes bytes, Locale locale) { if (bytes.bytes() >= 0) { if (bytes.terabytes() >= 1.0) { return unitString(bytes.terabytes(), "TB", locale); } if (bytes.gigabytes() >= 1.0) { return unitString(bytes.gigabytes(), "GB", locale); } if (bytes.megabytes() >= 1.0) { return unitString(bytes.megabytes(), "MB", locale); } if (bytes.kilobytes() >= 1.0) { return unitString(bytes.kilobytes(), "KB", locale); } return Long.toString(bytes.bytes()) + " bytes"; } else { return "N/A"; } } private static String unitString(final double value, final String units, final Locale locale) { return StringValue.valueOf(value, locale) + " " + units; } }