Java tutorial
/** This package is part of the application VIF. Copyright (C) 2011-2015, Benno Luthiger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.hip.vif.web.util; // NOPMD import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.sql.SQLException; import org.hip.kernel.bom.GeneralDomainObject; import org.hip.kernel.bom.QueryResult; import org.hip.kernel.exc.VException; import org.hip.vif.core.ApplicationConstants; import org.hip.vif.core.bom.DownloadTextHome; import org.hip.vif.core.exc.ProhibitedFileException; import org.hip.vif.core.service.PreferencesHandler; import org.hip.vif.web.Activator; import org.hip.vif.web.Constants; import org.hip.vif.web.interfaces.IBibliographyTask; import org.ripla.interfaces.IMessages; import org.ripla.web.util.Dialog; import org.ripla.web.util.Dialog.AbstractDialogWindow; import org.ripla.web.util.Dialog.DialogWindow; import org.ripla.web.util.RiplaViewHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.event.Transferable; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.acceptcriteria.AcceptAll; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.server.StreamVariable; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.DragAndDropWrapper; import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Html5File; import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.Upload; import com.vaadin.ui.Upload.FailedEvent; import com.vaadin.ui.Upload.FinishedEvent; import com.vaadin.ui.Upload.StartedEvent; import com.vaadin.ui.Upload.SucceededEvent; /** Displays file upload button and handles file upload. When the user selects a file to upload and a download file * exists already, a popup window is displayed to ask whether the old file has to be replaced by the new one. If no, the * newly upload file is discarded. * * @author Luthiger Created: 17.08.2011 */ @SuppressWarnings("serial") public class UploadComponent extends CustomComponent { // NOPMD private static final Logger LOG = LoggerFactory.getLogger(UploadComponent.class); private static final int MEGA = 1048576; private final HorizontalLayout layout; private final Component dropBox; private final Upload upload; private final Button downloadDelete; private final AbstractDialogWindow dialog; private File tempUpload; private boolean hasDownloads; private boolean uploadFinished; private FileInfo fileInfo; /** Constructor * * @param inDownloads {@link QueryResult} the existing download files to display * @param inTask {@link IBibliographyTask} * @throws VException * @throws SQLException */ public UploadComponent(final QueryResult inDownloads, final IBibliographyTask inTask) throws VException, SQLException { super(); hasDownloads = false; dialog = createDialog(inTask); layout = createLayout(); setCompositionRoot(layout); layout.setStyleName("vif-upload"); //$NON-NLS-1$ dropBox = createDropBox(inTask); layout.addComponent(dropBox); upload = createUpload(inTask); layout.addComponent(upload); Component lLast = upload; downloadDelete = createDeleteFileButton(inTask); if (inDownloads.hasMoreElements()) { // add button to delete file and download link to download layout hasDownloads = true; final GeneralDomainObject lDownload = inDownloads.next(); final DownloadFileLink lDownloadLink = new DownloadFileLink( BeanWrapperHelper.getString(DownloadTextHome.KEY_LABEL, lDownload), BeanWrapperHelper.getLong(DownloadTextHome.KEY_ID, lDownload)); layout.addComponent(downloadDelete); layout.addComponent(lDownloadLink); lLast = lDownloadLink; } else { final Component lSpace = RiplaViewHelper.createSpacer(); layout.addComponent(lSpace); lLast = lSpace; } lLast.setWidth("100%"); //$NON-NLS-1$ layout.setExpandRatio(lLast, 1); layout.setComponentAlignment(lLast, Alignment.MIDDLE_LEFT); } private Button createDeleteFileButton(final IBibliographyTask inTask) { final IMessages lMessages = Activator.getMessages(); final Button outDelete = new Button(lMessages.getMessage("ui.button.delete.file")); //$NON-NLS-1$ outDelete.addClickListener(new Button.ClickListener() { @Override public void buttonClick(final ClickEvent inEvent) { // NOPMD if (inTask.deleteDownloads()) { // update view component layout.removeAllComponents(); addComponents(dropBox, upload, RiplaViewHelper.createSpacer()); hasDownloads = false; } else { Notification.show(lMessages.getMessage("errmsg.save.general"), //$NON-NLS-1$ Notification.Type.WARNING_MESSAGE); } } }); return outDelete; } private HorizontalLayout createLayout() { final HorizontalLayout outLayout = new HorizontalLayout(); outLayout.setSpacing(true); outLayout.setWidth("100%"); //$NON-NLS-1$ return outLayout; } private void addComponents(final Component... inComponents) { // NOPMD for (final Component lComponent : inComponents) { layout.addComponent(lComponent); } final Component lLast = inComponents[inComponents.length - 1]; lLast.setWidth("100%"); //$NON-NLS-1$ layout.setExpandRatio(lLast, 1); layout.setComponentAlignment(lLast, Alignment.MIDDLE_LEFT); } private AbstractDialogWindow createDialog(final IBibliographyTask inTask) { final IMessages lMessages = Activator.getMessages(); final Dialog.DialogWindow outDialog = (DialogWindow) Dialog.openQuestion( lMessages.getMessage("ui.upload.dialog.title"), lMessages.getMessage("ui.upload.dialog.question")); //$NON-NLS-1$ //$NON-NLS-2$ outDialog.addYesListener(new Button.ClickListener() { @Override public void buttonClick(final ClickEvent inEvent) { // NOPMD dialog.setVisible(false); checkUploadState(); if (tempUpload != null) { handleUpload(inTask, true); } } }); outDialog.addNoListener(new Button.ClickListener() { @Override public void buttonClick(final ClickEvent inEvent) { // NOPMD dialog.setVisible(false); checkUploadState(); handleDeleteTemp(); } }); return outDialog; } private OutputStream createStream(final String inFilename) { if (inFilename.length() != 0) { try { tempUpload = File.createTempFile(Constants.TMP_UPLOAD_PREFIX, Constants.TMP_UPLOAD_SUFFIX); return new FileOutputStream(tempUpload); } catch (final IOException exc) { LOG.error("Could not upload file '{}'.", inFilename, exc); //$NON-NLS-1$ } } return new NoOpStream(); } private Component createDropBox(final IBibliographyTask inTask) { final CssLayout lDropPane = new CssLayout(); lDropPane.setWidth("200px"); //$NON-NLS-1$ lDropPane.setHeight("40px"); //$NON-NLS-1$ lDropPane.addStyleName("v-textfield"); //$NON-NLS-1$ final Label lHint = new Label(Activator.getMessages().getMessage("ui.upload.drop.box")); //$NON-NLS-1$ lHint.setStyleName("vif-drop-hint"); //$NON-NLS-1$ lDropPane.addComponent(lHint); final DragAndDropWrapper outDrop = new DragAndDropWrapper(lDropPane); outDrop.setDropHandler(new DropHandler() { @Override public AcceptCriterion getAcceptCriterion() { // NOPMD return AcceptAll.get(); } @Override public void drop(final DragAndDropEvent inEvent) { // NOPMD final Transferable lTransferable = inEvent.getTransferable(); if (lTransferable instanceof WrapperTransferable) { final Html5File[] lFiles = ((WrapperTransferable) lTransferable).getFiles(); for (final Html5File lFile : lFiles) { lFile.setStreamVariable(createStreamVariable(lFile.getFileName(), inTask)); } } } }); outDrop.setSizeUndefined(); outDrop.setImmediate(true); return outDrop; } private Upload createUpload(final IBibliographyTask inTask) { final Upload outUpload = new Upload(); outUpload.setWidthUndefined(); outUpload.setReceiver(new Upload.Receiver() { @Override public OutputStream receiveUpload(final String inFilename, // NOPMD final String inMimeType) { return createStream(inFilename); } }); final String lCaption = Activator.getMessages().getMessage("ui.upload.button.lbl"); //$NON-NLS-1$ outUpload.setButtonCaption(lCaption); outUpload.setImmediate(true); outUpload.setStyleName("vif-upload"); //$NON-NLS-1$ outUpload.addStartedListener(new Upload.StartedListener() { @Override public void uploadStarted(final StartedEvent inEvent) { // NOPMD fileInfo = new FileInfo(inEvent.getFilename(), inEvent.getMIMEType()); tempUpload = null; // NOPMD uploadFinished = false; outUpload.setVisible(false); if (hasDownloads) { dialog.setVisible(true); // FF } } }); outUpload.addFinishedListener(new Upload.FinishedListener() { @Override public void uploadFinished(final FinishedEvent inEvent) { // NOPMD uploadFinished = true; outUpload.setVisible(true); } }); outUpload.addSucceededListener(new Upload.SucceededListener() { @Override public void uploadSucceeded(final SucceededEvent inEvent) { // NOPMD if (!hasDownloads) { handleUpload(inTask, false); } } }); outUpload.addFailedListener(new Upload.FailedListener() { @Override public void uploadFailed(final FailedEvent inEvent) { // NOPMD handleDeleteTemp(); } }); return outUpload; } private StreamVariable createStreamVariable(final String inFileName, // NOPMD final IBibliographyTask inTask) { return new StreamVariable() { @Override public OutputStream getOutputStream() { // NOPMD return createStream(inFileName); } @Override public void streamingStarted(final StreamingStartEvent inEvent) { // NOPMD fileInfo = new FileInfo(inEvent.getFileName(), inEvent.getMimeType()); tempUpload = null; // NOPMD uploadFinished = false; upload.setVisible(false); if (hasDownloads) { dialog.setVisible(true); // Google } } @Override public void streamingFinished(final StreamingEndEvent inEvent) { // NOPMD uploadFinished = true; upload.setVisible(true); if (!hasDownloads) { handleUpload(inTask, false); } } @Override public void streamingFailed(final StreamingErrorEvent inEvent) { // NOPMD handleDeleteTemp(); } @Override public void onProgress(final StreamingProgressEvent inEvent) { // NOPMD // intentionally left empty } @Override public boolean listenProgress() { // NOPMD return false; } @Override public boolean isInterrupted() { // NOPMD return false; } }; } private void handleDeleteTemp() { if (tempUpload != null) { if (!tempUpload.delete()) { tempUpload.deleteOnExit(); } } } private void handleUpload(final IBibliographyTask inTask, final boolean inDeleteDownloads) { final IMessages lMessages = Activator.getMessages(); // check upload file size if (tempUpload.length() > getMaxSize() * MEGA) { handleDeleteTemp(); Notification.show(lMessages.getFormattedMessage("errmsg.upload.exceeded", getMaxSize()), //$NON-NLS-1$ Notification.Type.WARNING_MESSAGE); return; } try { final Long lDownloadID = inTask.saveFileUpload(tempUpload, fileInfo.fileName, fileInfo.mimeType, inDeleteDownloads); if (lDownloadID == 0) { // show error notification Notification.show(lMessages.getMessage("errmsg.save.general"), Notification.Type.ERROR_MESSAGE);//$NON-NLS-1$ } else { // update download layout hasDownloads = true; layout.removeAllComponents(); addComponents(dropBox, upload, downloadDelete, new DownloadFileLink(fileInfo.fileName, lDownloadID)); } } catch (final ProhibitedFileException exc) { Notification.show(lMessages.getMessage("errmsg.upload.prohibited"), Notification.Type.ERROR_MESSAGE);//$NON-NLS-1$ } } private void checkUploadState() { while (!uploadFinished) { try { Thread.sleep(100); } catch (final InterruptedException exc) { // intentionally left empty } } } private long getMaxSize() { try { return Long.parseLong(PreferencesHandler.INSTANCE.get(PreferencesHandler.KEY_UPLOAD_QUOTA)); } catch (final NumberFormatException exc) { LOG.error("Error encountered while retrieving the upload quoata preference!", exc); //$NON-NLS-1$ } catch (final IOException exc) { LOG.error("Error encountered while retrieving the upload quoata preference!", exc); //$NON-NLS-1$ } return ApplicationConstants.DFLT_UPLOADE_QUOTA; } @Override public void attach() { // NOPMD super.attach(); if (hasDownloads) { dialog.setVisible(false); dialog.center(); } } @Override public void detach() { // NOPMD super.detach(); dialog.close(); } // --- private static class NoOpStream extends OutputStream { // NOPMD @Override public void write(final int inByte) throws IOException { // NOPMD // No operation } } /** Parameter object, e.g. "2011-06-26_11-04-43_20.jpg" :: "image/jpeg" * * @author Luthiger Created: 22.08.2011 */ private static class FileInfo { private final String fileName; private final String mimeType; FileInfo(final String inFileName, final String inMimeType) { fileName = inFileName; mimeType = inMimeType; } } }