001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.platform.ui.web.component.file; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.List; 025 026import javax.faces.application.Application; 027import javax.faces.component.UIComponent; 028import javax.faces.component.UIInput; 029import javax.faces.component.html.HtmlInputFile; 030import javax.faces.context.FacesContext; 031import javax.faces.context.ResponseWriter; 032import javax.faces.validator.Validator; 033 034import org.apache.commons.lang.StringUtils; 035import org.nuxeo.ecm.core.api.Blob; 036import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 037 038/** 039 * JSF File Upload mechanism based on a standard HTML {@code <input>} field. 040 * 041 * @since 7.2 042 */ 043public class HTMLBlobUploader implements JSFBlobUploader { 044 045 protected static final String UPLOAD_FACET_NAME = "upload"; 046 047 public HTMLBlobUploader(String id) { 048 } 049 050 @Override 051 public String getChoice() { 052 return InputFileChoice.UPLOAD; 053 } 054 055 @Override 056 public void hookSubComponent(UIInput parent) { 057 FacesContext faces = FacesContext.getCurrentInstance(); 058 Application app = faces.getApplication(); 059 ComponentUtils.initiateSubComponent(parent, UPLOAD_FACET_NAME, 060 app.createComponent(faces, HtmlInputFile.COMPONENT_TYPE, NXFileRenderer.RENDERER_TYPE)); 061 } 062 063 @Override 064 public void encodeBeginUpload(UIInput parent, FacesContext context, String onChange) throws IOException { 065 UIComponent facet = parent.getFacet(UPLOAD_FACET_NAME); 066 if (!(facet instanceof HtmlInputFile)) { 067 return; 068 } 069 HtmlInputFile inputFile = (HtmlInputFile) facet; 070 071 // not ours to close 072 @SuppressWarnings("resource") 073 ResponseWriter writer = context.getResponseWriter(); 074 075 // encode validators info 076 long sizeMax = 0L; 077 String sizeConstraint = null; 078 List<String> authorizedExtensions = new ArrayList<String>(); 079 List<String> unauthorizedExtensions = new ArrayList<String>(); 080 boolean hidden = false; 081 for (Validator val : parent.getValidators()) { 082 if (val instanceof InputFileSizeValidator) { 083 InputFileSizeValidator sizeVal = (InputFileSizeValidator) val; 084 long currentSizeMax = sizeVal.getMaxSizeBytes(); 085 if (currentSizeMax > sizeMax) { 086 sizeMax = currentSizeMax; 087 sizeConstraint = sizeVal.getMaxSize(); 088 } 089 } else if (val instanceof InputFileMimetypeValidator) { 090 InputFileMimetypeValidator extVal = (InputFileMimetypeValidator) val; 091 hidden = extVal.isHidden(); 092 if (extVal.isAuthorized()) { 093 authorizedExtensions.addAll(Arrays.asList(extVal.getExtensions())); 094 } else { 095 unauthorizedExtensions.addAll(Arrays.asList(extVal.getExtensions())); 096 } 097 } 098 } 099 List<String> constraints = new ArrayList<String>(); 100 if (sizeConstraint != null) { 101 constraints.add(ComponentUtils.translate(context, "label.inputFile.maxSize", sizeConstraint)); 102 } 103 if (!hidden && (!authorizedExtensions.isEmpty() || !unauthorizedExtensions.isEmpty())) { 104 if (!authorizedExtensions.isEmpty()) { 105 constraints.add(ComponentUtils.translate(context, "label.inputFile.authorizedExtensions", 106 StringUtils.join(authorizedExtensions.toArray(), ", "))); 107 } 108 if (!unauthorizedExtensions.isEmpty()) { 109 constraints.add(ComponentUtils.translate(context, "label.inputFile.unauthorizedExtensions", 110 StringUtils.join(unauthorizedExtensions.toArray(), ", "))); 111 } 112 } 113 if (constraints.size() > 0) { 114 writer.write("("); 115 writer.write(StringUtils.join(constraints.toArray(), ", ")); 116 writer.write(")"); 117 writer.write(ComponentUtils.WHITE_SPACE_CHARACTER); 118 } 119 120 // encode upload component 121 inputFile.setOnchange(onChange); 122 // TODO: add size limit info 123 ComponentUtils.encodeComponent(context, inputFile); 124 } 125 126 @Override 127 public void validateUpload(UIInput parent, FacesContext context, InputFileInfo submitted) { 128 UIComponent facet = parent.getFacet(UPLOAD_FACET_NAME); 129 if (!(facet instanceof HtmlInputFile)) { 130 return; 131 } 132 HtmlInputFile inputFile = (HtmlInputFile) facet; 133 Object submittedFile = inputFile.getSubmittedValue(); 134 if (!(submittedFile instanceof Blob)) { 135 return; 136 } 137 Blob sblob = (Blob) submittedFile; 138 if (sblob.getLength() == 0) { 139 String message = context.getPartialViewContext().isAjaxRequest() ? InputFileInfo.INVALID_WITH_AJAX_MESSAGE 140 : InputFileInfo.EMPTY_FILE_MESSAGE; 141 ComponentUtils.addErrorMessage(context, parent, message); 142 parent.setValid(false); 143 return; 144 } 145 submitted.setBlob(sblob); 146 submitted.setFilename(sblob.getFilename()); 147 submitted.setMimeType(sblob.getMimeType()); 148 } 149 150 @Override 151 public boolean isEnabled() { 152 return true; 153 } 154 155}