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 onClick) 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.setOnclick(onClick);
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.INVALID_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}