001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Florent Guillaume 016 */ 017package org.nuxeo.ecm.platform.ui.web.component.file; 018 019import java.io.IOException; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.List; 023 024import javax.faces.application.Application; 025import javax.faces.component.UIComponent; 026import javax.faces.component.UIInput; 027import javax.faces.component.html.HtmlInputFile; 028import javax.faces.context.FacesContext; 029import javax.faces.context.ResponseWriter; 030import javax.faces.validator.Validator; 031 032import org.apache.commons.lang.StringUtils; 033import org.nuxeo.ecm.core.api.Blob; 034import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 035 036/** 037 * JSF File Upload mechanism based on a standard HTML {@code <input>} field. 038 * 039 * @since 7.2 040 */ 041public class HTMLBlobUploader implements JSFBlobUploader { 042 043 protected static final String UPLOAD_FACET_NAME = "upload"; 044 045 public HTMLBlobUploader(String id) { 046 } 047 048 @Override 049 public String getChoice() { 050 return InputFileChoice.UPLOAD; 051 } 052 053 @Override 054 public void hookSubComponent(UIInput parent) { 055 FacesContext faces = FacesContext.getCurrentInstance(); 056 Application app = faces.getApplication(); 057 ComponentUtils.initiateSubComponent(parent, UPLOAD_FACET_NAME, 058 app.createComponent(faces, HtmlInputFile.COMPONENT_TYPE, NXFileRenderer.RENDERER_TYPE)); 059 } 060 061 @Override 062 public void encodeBeginUpload(UIInput parent, FacesContext context, String onClick) throws IOException { 063 UIComponent facet = parent.getFacet(UPLOAD_FACET_NAME); 064 if (!(facet instanceof HtmlInputFile)) { 065 return; 066 } 067 HtmlInputFile inputFile = (HtmlInputFile) facet; 068 069 // not ours to close 070 @SuppressWarnings("resource") 071 ResponseWriter writer = context.getResponseWriter(); 072 073 // encode validators info 074 long sizeMax = 0L; 075 String sizeConstraint = null; 076 List<String> authorizedExtensions = new ArrayList<String>(); 077 List<String> unauthorizedExtensions = new ArrayList<String>(); 078 boolean hidden = false; 079 for (Validator val : parent.getValidators()) { 080 if (val instanceof InputFileSizeValidator) { 081 InputFileSizeValidator sizeVal = (InputFileSizeValidator) val; 082 long currentSizeMax = sizeVal.getMaxSizeBytes(); 083 if (currentSizeMax > sizeMax) { 084 sizeMax = currentSizeMax; 085 sizeConstraint = sizeVal.getMaxSize(); 086 } 087 } else if (val instanceof InputFileMimetypeValidator) { 088 InputFileMimetypeValidator extVal = (InputFileMimetypeValidator) val; 089 hidden = extVal.isHidden(); 090 if (extVal.isAuthorized()) { 091 authorizedExtensions.addAll(Arrays.asList(extVal.getExtensions())); 092 } else { 093 unauthorizedExtensions.addAll(Arrays.asList(extVal.getExtensions())); 094 } 095 } 096 } 097 List<String> constraints = new ArrayList<String>(); 098 if (sizeConstraint != null) { 099 constraints.add(ComponentUtils.translate(context, "label.inputFile.maxSize", sizeConstraint)); 100 } 101 if (!hidden && (!authorizedExtensions.isEmpty() || !unauthorizedExtensions.isEmpty())) { 102 if (!authorizedExtensions.isEmpty()) { 103 constraints.add(ComponentUtils.translate(context, "label.inputFile.authorizedExtensions", 104 StringUtils.join(authorizedExtensions.toArray(), ", "))); 105 } 106 if (!unauthorizedExtensions.isEmpty()) { 107 constraints.add(ComponentUtils.translate(context, "label.inputFile.unauthorizedExtensions", 108 StringUtils.join(unauthorizedExtensions.toArray(), ", "))); 109 } 110 } 111 if (constraints.size() > 0) { 112 writer.write("("); 113 writer.write(StringUtils.join(constraints.toArray(), ", ")); 114 writer.write(")"); 115 writer.write(ComponentUtils.WHITE_SPACE_CHARACTER); 116 } 117 118 // encode upload component 119 inputFile.setOnclick(onClick); 120 // TODO: add size limit info 121 ComponentUtils.encodeComponent(context, inputFile); 122 } 123 124 @Override 125 public void validateUpload(UIInput parent, FacesContext context, InputFileInfo submitted) { 126 UIComponent facet = parent.getFacet(UPLOAD_FACET_NAME); 127 if (!(facet instanceof HtmlInputFile)) { 128 return; 129 } 130 HtmlInputFile inputFile = (HtmlInputFile) facet; 131 Object submittedFile = inputFile.getSubmittedValue(); 132 if (!(submittedFile instanceof Blob)) { 133 return; 134 } 135 Blob sblob = (Blob) submittedFile; 136 if (sblob.getLength() == 0) { 137 String message = context.getPartialViewContext().isAjaxRequest() ? InputFileInfo.INVALID_WITH_AJAX_MESSAGE 138 : InputFileInfo.INVALID_FILE_MESSAGE; 139 ComponentUtils.addErrorMessage(context, parent, message); 140 parent.setValid(false); 141 return; 142 } 143 submitted.setBlob(sblob); 144 submitted.setFilename(sblob.getFilename()); 145 submitted.setMimeType(sblob.getMimeType()); 146 } 147 148 @Override 149 public boolean isEnabled() { 150 return true; 151 } 152 153}