com.liferay.mail.vaadin.Composer.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.mail.vaadin.Composer.java

Source

/**
 * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.mail.vaadin;

import com.liferay.mail.MailException;
import com.liferay.mail.model.Account;
import com.liferay.mail.model.MailFile;
import com.liferay.mail.model.Message;
import com.liferay.mail.service.AccountLocalServiceUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;

import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.terminal.StreamResource;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.ProgressIndicator;
import com.vaadin.ui.RichTextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Upload.FailedEvent;
import com.vaadin.ui.Upload.FinishedEvent;
import com.vaadin.ui.Upload.StartedEvent;
import com.vaadin.ui.Upload;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.Window;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.text.DecimalFormat;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

/**
 * @author Henri Sara
 */
public class Composer extends CustomComponent {

    private static Log _log = LogFactoryUtil.getLog(Composer.class);

    private static final Object ACCOUNT_NAME_ID = "address";

    private List<AttachmentLayout> attachments = new ArrayList<AttachmentLayout>();

    private LinkedHashSet<ComposerListener> listeners = new LinkedHashSet<ComposerListener>();

    // UI
    private VerticalLayout mainLayout;
    private VerticalLayout innerLayout;
    private HorizontalLayout actionsLayout;
    private Button send;
    private Button save;
    private Button cancel;
    private VerticalLayout messageLayout;
    private RichTextArea message;
    private VerticalLayout bottomLayout;
    private HorizontalLayout subjectLayout;
    private Button addAttachment;
    private TextField subject;
    private TextField toField;
    private TextField ccField;
    private TextField bccField;
    private FormLayout recipientsLayout;
    private HorizontalLayout fromLayout;
    private ComboBox from;
    private long draftMessageId = 0;

    /**
     * The constructor should first build the main layout, set the composition
     * root and then do any custom initialization. The constructor will not be
     * automatically regenerated by the visual editor.
     */
    public Composer() {

        // The layout was originally composed with the visual editor and later
        // converted to hand-edited form.

        buildMainLayout();
        setCompositionRoot(mainLayout);
        mainLayout.setMargin(false);

        fromLayout.setMargin(true);
        from.setNullSelectionAllowed(false);
        initAccounts();

        innerLayout.setMargin(true);
        innerLayout.setHeight("100.0%");
        mainLayout.setExpandRatio(innerLayout, 1.0f);

        // Recipients
        recipientsLayout.setMargin(false, false, true, false);

        // Subject
        subjectLayout.setMargin(false);
        subjectLayout.setSpacing(true);
        subject.setInputPrompt(Lang.get("subject"));
        subjectLayout.setExpandRatio(subject, 1.0f);

        // Message
        innerLayout.setExpandRatio(messageLayout, 1.0f);

        bottomLayout.setMargin(true);
        bottomLayout.setSpacing(true);

        // Controls
        actionsLayout.setExpandRatio(cancel, 1.0f);
        actionsLayout.setComponentAlignment(cancel, "right");
        actionsLayout.setSpacing(true);
        actionsLayout.setMargin(true);

        cancel.addListener(new Button.ClickListener() {

            public void buttonClick(ClickEvent event) {

                final ConfirmDialog confirm = new ConfirmDialog(Lang.get("confirm"), Lang.get("discard-draft"),
                        Lang.get("are-you-sure-you-want-to-discard-draft"));

                confirm.addConfirmButtonListener(new ClickListener() {

                    public void buttonClick(ClickEvent event) {

                        confirm.closeDialog();
                        fireDiscard();
                    }
                });

                Controller.get().getApplication().getMainWindow().addWindow(confirm);
            }
        });
        save.addListener(new Button.ClickListener() {

            public void buttonClick(ClickEvent event) {

                fireSave(false);
            }
        });
        send.addListener(new Button.ClickListener() {

            public void buttonClick(ClickEvent event) {

                fireSend(false);
            }
        });
    }

    private VerticalLayout buildMainLayout() {

        // common part: create layout
        mainLayout = new VerticalLayout();
        mainLayout.setHeight("100%");

        // top-level component properties
        setHeight("-1px");
        setWidth("100.0%");
        setHeight("100.0%");

        // fromLayout
        fromLayout = buildFromLayout();
        fromLayout.setStyleName("black");
        fromLayout.setImmediate(false);
        fromLayout.setHeight("-1px");
        fromLayout.setWidth("100.0%");
        mainLayout.addComponent(fromLayout);

        // innerLayout
        innerLayout = new VerticalLayout();
        innerLayout.setImmediate(false);
        innerLayout.setHeight("-1px");
        innerLayout.setWidth("100.0%");
        mainLayout.addComponent(innerLayout);

        // recipientsLayout
        recipientsLayout = buildRecipientsLayout();
        recipientsLayout.setImmediate(false);
        recipientsLayout.setHeight("-1px");
        recipientsLayout.setWidth("100.0%");
        innerLayout.addComponent(recipientsLayout);

        // subjectLayout
        subjectLayout = buildSubjectLayout();
        subjectLayout.setStyleName("blue");
        subjectLayout.setImmediate(false);
        subjectLayout.setHeight("-1px");
        subjectLayout.setWidth("100.0%");
        innerLayout.addComponent(subjectLayout);

        // messageLayout
        messageLayout = buildMessageLayout();
        messageLayout.setImmediate(false);
        messageLayout.setHeight("100.0%");
        messageLayout.setWidth("100.0%");
        innerLayout.addComponent(messageLayout);

        // bottomLayout
        bottomLayout = new VerticalLayout();
        bottomLayout.setSpacing(true);
        bottomLayout.setStyleName("blue");
        bottomLayout.setWidth("100.0%");
        innerLayout.addComponent(bottomLayout);
        // bottomLayout.setVisible(false);

        // addAttachment
        addAttachment = new Button(Lang.get("add-attachment"), new Button.ClickListener() {

            public void buttonClick(ClickEvent event) {

                addAttachment();
            }

        });
        addAttachment.setStyleName("small");
        addAttachment.setImmediate(true);
        addAttachment.setHeight("-1px");
        addAttachment.setWidth("-1px");
        bottomLayout.addComponent(addAttachment);

        // actionsLayout
        actionsLayout = buildActionsLayout();
        actionsLayout.setStyleName("black");
        actionsLayout.setImmediate(false);
        actionsLayout.setHeight("-1px");
        actionsLayout.setWidth("100.0%");
        mainLayout.addComponent(actionsLayout);

        return mainLayout;
    }

    private HorizontalLayout buildFromLayout() {

        // common part: create layout
        fromLayout = new HorizontalLayout();
        fromLayout.setSpacing(true);

        Label fromLabel = new Label(Lang.get("from"));
        fromLabel.setSizeUndefined();
        fromLayout.addComponent(fromLabel);

        // from
        from = new ComboBox();
        from.setDescription(Lang.get("the-account-to-send-the-message-from"));
        from.setImmediate(true);
        from.setHeight("-1px");
        from.setWidth("100.0%");
        fromLayout.addComponent(from);
        fromLayout.setExpandRatio(from, 1.0f);

        return fromLayout;
    }

    private FormLayout buildRecipientsLayout() {

        // common part: create layout
        recipientsLayout = new FormLayout();
        recipientsLayout.setSpacing(true);

        toField = new TextField();
        toField.setImmediate(false);
        toField.setHeight("-1px");
        toField.setWidth("100.0%");
        toField.setCaption(Lang.get("to"));
        recipientsLayout.addComponent(toField);

        ccField = new TextField();
        ccField.setImmediate(false);
        ccField.setHeight("-1px");
        ccField.setWidth("100.0%");
        ccField.setCaption(Lang.get("cc"));
        recipientsLayout.addComponent(ccField);

        bccField = new TextField();
        bccField.setImmediate(false);
        bccField.setHeight("-1px");
        bccField.setWidth("100.0%");
        bccField.setCaption(Lang.get("bcc"));
        recipientsLayout.addComponent(bccField);

        return recipientsLayout;
    }

    private HorizontalLayout buildSubjectLayout() {

        // common part: create layout
        subjectLayout = new HorizontalLayout();

        // subject
        subject = new TextField();
        subject.setImmediate(false);
        subject.setHeight("-1px");
        subject.setWidth("100.0%");
        subjectLayout.addComponent(subject);

        return subjectLayout;
    }

    private VerticalLayout buildMessageLayout() {

        // common part: create layout
        messageLayout = new VerticalLayout();

        // message
        message = new RichTextArea();
        message.setImmediate(false);
        message.setHeight("100.0%");
        message.setWidth("100.0%");
        messageLayout.addComponent(message);

        return messageLayout;
    }

    private HorizontalLayout buildActionsLayout() {

        // common part: create layout
        actionsLayout = new HorizontalLayout();

        // cancel
        cancel = new Button();
        cancel.setImmediate(true);
        cancel.setHeight("-1px");
        cancel.setWidth("-1px");
        cancel.setCaption(Lang.get("discard"));
        actionsLayout.addComponent(cancel);

        // save
        save = new Button();
        save.setImmediate(true);
        save.setHeight("-1px");
        save.setWidth("-1px");
        save.setCaption("Save");
        actionsLayout.addComponent(save);

        // send
        send = new Button();
        send.setStyleName("primary");
        send.setImmediate(true);
        send.setHeight("-1px");
        send.setWidth("-1px");
        send.setCaption(Lang.get("send"));
        actionsLayout.addComponent(send);

        return actionsLayout;
    }

    // non UI-building follows:

    public String getTo() {
        return (String) toField.getValue();
    }

    public String getCc() {
        return (String) ccField.getValue();
    }

    public String getBcc() {
        return (String) bccField.getValue();
    }

    public void setTo(String value) {
        toField.setValue(value);
    }

    public void setCc(String value) {
        ccField.setValue(value);
    }

    public void setBcc(String value) {
        bccField.setValue(value);
    }

    public List<MailFile> getAttachments() {

        List<MailFile> a = new ArrayList<MailFile>();
        for (AttachmentLayout attachment : attachments) {
            if (attachment.hasFile()) {
                MailFile mf = new MailFile(attachment.getFile(), attachment.getFilename(), attachment.getSize());
                a.add(mf);
            }
        }
        return a;
    }

    public void setMessage(String message) {

        this.message.setValue(message);
    }

    public String getMessage() {

        return (String) message.getValue();
    }

    public void setDraftMessageId(long id) {

        draftMessageId = id;
    }

    public long getDraftMessageId() {

        return draftMessageId;
    }

    public void setSubject(String subject) {

        this.subject.setValue(subject);
    }

    public String getSubject() {

        return (String) subject.getValue();
    }

    private void initAccounts() {

        List<Account> accounts = null;
        try {
            accounts = AccountLocalServiceUtil.getAccounts(Controller.get().getUser().getUserId());
        } catch (SystemException e) {
            getApplication().getMainWindow().showNotification(Lang.get("unable-to-access-account"),
                    Notification.TYPE_ERROR_MESSAGE);
            _log.warn("Unable to access account", e);
            fireDiscard();
        }
        BeanItemContainer<Account> bi = new BeanItemContainer<Account>(accounts);
        from.setContainerDataSource(bi);
        from.setItemCaptionPropertyId(ACCOUNT_NAME_ID);
        from.setValue(accounts.get(0));
    }

    public Account getFrom() {

        return (Account) from.getValue();
    }

    private void addAttachment() {

        AttachmentLayout attachment = new AttachmentLayout();
        bottomLayout.addComponent(attachment, attachments.size());
        attachments.add(attachment);
    }

    private void removeAttachment(AttachmentLayout attachment) {

        attachment.delete();
        attachments.remove(attachment);
        bottomLayout.removeComponent(attachment);
    }

    public void addListener(ComposerListener listener) {

        listeners.add(listener);
    }

    public void removeListener(ComposerListener listener) {

        listeners.remove(listener);
    }

    private void fireDiscard() {

        for (ComposerListener listener : listeners) {
            listener.messageDiscarded(this);
        }
    }

    private void fireSave(boolean skipPasswordCheck) {
        if (!getFrom().isSavePassword() && !skipPasswordCheck) {
            Account account = getFrom();
            String password = null;
            try {
                password = Controller.get().getPasswordRetriever().getPassword(account.getAccountId());
            } catch (PortalException e2) {
            } catch (SystemException e2) {
            }

            if (password != null) {
                try {
                    Controller.get().getMailManager().storePassword(account.getAccountId(), password);
                    Controller.get().getAccountManager().updateAccount(account, Controller.get());
                    Controller.get().getMailManager().synchronizeAccount(account.getAccountId());
                } catch (PortalException e1) {
                    Controller.get().showError(Lang.get("unable-to-synchronize-account"), e1);
                } catch (SystemException e1) {
                    Controller.get().showError(Lang.get("unable-to-synchronize-account"), e1);
                }
            } else {
                PasswordPrompt prompt = new PasswordPrompt(account);
                prompt.addListener(new Window.CloseListener() {
                    //@Override
                    public void windowClose(CloseEvent e) {
                        PasswordPrompt prompt = (PasswordPrompt) e.getWindow();
                        if (prompt.getStatus() == PasswordPrompt.Status.VALIDATED) {
                            fireSave(true);
                        }
                    }
                });
                getWindow().addWindow(prompt);
                prompt.center();
                return;
            }
        }

        Message msg = null;
        try {
            msg = MessageUtil.saveOrSendMessage(getFrom(), getTo(), getCc(), getBcc(), getSubject(), getMessage(),
                    getAttachments(), false, draftMessageId);

            for (ComposerListener listener : listeners) {
                listener.messageSaved(this, msg);
            }
        } catch (MailException me) {
            if (me.getType() == MailException.MESSAGE_HAS_NO_RECIPIENTS) {
                getApplication().getMainWindow().showNotification(Lang.get("please-specify-at-least-one-recipient"),
                        me.getMessage(), Notification.TYPE_ERROR_MESSAGE);
            } else {
                getApplication().getMainWindow().showNotification(Lang.get("unable-to-save-draft"), me.getMessage(),
                        Notification.TYPE_ERROR_MESSAGE);
            }

            return;
        } catch (PortalException e) {
            _log.error(e);
            getApplication().getMainWindow().showNotification(Lang.get("unable-to-save-draft"), e.getMessage(),
                    Notification.TYPE_ERROR_MESSAGE);
        } catch (SystemException e) {
            _log.error(e);
            getApplication().getMainWindow().showNotification(Lang.get("unable-to-save-draft"), e.getMessage(),
                    Notification.TYPE_ERROR_MESSAGE);
        }
    }

    private void fireSend(boolean skipPasswordCheck) {
        if (!getFrom().isSavePassword() && !skipPasswordCheck) {
            /*
             *   Password not saved, try to get it from the password retriever or from the user
             */
            Account account = getFrom();
            String password = null;
            try {
                password = Controller.get().getPasswordRetriever().getPassword(account.getAccountId());
            } catch (PortalException e2) {
                // Don't do anything, the password prompt will be displayed later
            } catch (SystemException e2) {
                // Don't do anything, the password prompt will be displayed later
            }

            if (password != null) {
                try {
                    Controller.get().getMailManager().storePassword(account.getAccountId(), password);
                    Controller.get().getAccountManager().updateAccount(account, Controller.get());
                    Controller.get().getMailManager().synchronizeAccount(account.getAccountId());
                } catch (PortalException e1) {
                    Controller.get().showError(Lang.get("unable-to-synchronize-account"), e1);
                } catch (SystemException e1) {
                    Controller.get().showError(Lang.get("unable-to-synchronize-account"), e1);
                }
            } else {
                PasswordPrompt prompt = new PasswordPrompt(account);
                prompt.addListener(new Window.CloseListener() {
                    public void windowClose(CloseEvent e) {
                        PasswordPrompt prompt = (PasswordPrompt) e.getWindow();
                        if (prompt.getStatus() == PasswordPrompt.Status.VALIDATED) {
                            fireSend(true);
                        }
                    }
                });
                getWindow().addWindow(prompt);
                prompt.center();
                return;
            }
        }

        Message msg = null;
        try {
            msg = MessageUtil.saveOrSendMessage(getFrom(), getTo(), getCc(), getBcc(), getSubject(), getMessage(),
                    getAttachments(), true, draftMessageId);

            for (ComposerListener listener : listeners) {
                listener.messageSent(this, msg);
            }
        } catch (MailException me) {
            if (me.getType() == MailException.MESSAGE_HAS_NO_RECIPIENTS) {
                getApplication().getMainWindow().showNotification(Lang.get("please-specify-at-least-one-recipient"),
                        me.getMessage(), Notification.TYPE_ERROR_MESSAGE);
            } else if (me.getType() == MailException.MESSAGE_INVALID_ADDRESS) {
                getApplication().getMainWindow().showNotification(Lang
                        .get("please-make-sure-the-following-address-is-properly" + "-formatted", me.getValue()),
                        me.getMessage(), Notification.TYPE_ERROR_MESSAGE);

            } else {
                getApplication().getMainWindow().showNotification(Lang.get("unable-to-send-message"),
                        me.getMessage(), Notification.TYPE_ERROR_MESSAGE);
                return;
            }
        } catch (PortalException e) {
            _log.error(e);
            getApplication().getMainWindow().showNotification(Lang.get("unable-to-send-message"), e.getMessage(),
                    Notification.TYPE_ERROR_MESSAGE);
        } catch (SystemException e) {
            _log.error(e);
            getApplication().getMainWindow().showNotification(Lang.get("unable-to-send-message"), e.getMessage(),
                    Notification.TYPE_ERROR_MESSAGE);
        }
    }

    public class AttachmentLayout extends HorizontalLayout {

        private Buffer buffer = new Buffer();

        private Upload upload = new Upload(null, buffer);

        ProgressIndicator progress = new ProgressIndicator();

        private long size = 0;
        private String filename = null;

        AttachmentLayout() {

            setStyleName("blue");
            setSpacing(true);
            setWidth("100.0%");

            addComponent(upload);

            progress.setPollingInterval(500);
            progress.setWidth("100.0%");

            upload.addListener(new Upload.StartedListener() {

                public void uploadStarted(StartedEvent event) {

                    addComponent(progress);
                    setExpandRatio(progress, 1.0f);
                    setComponentAlignment(progress, "middle center");
                    // upload.setVisible(false);
                    progress.setIndeterminate(false);
                }

            });

            upload.addListener(new Upload.ProgressListener() {

                public void updateProgress(long readBytes, long contentLength) {

                    float p = (float) readBytes / contentLength;
                    progress.setValue(p);
                }

            });

            upload.addListener(new Upload.FailedListener() {

                public void uploadFailed(FailedEvent event) {

                    progress.setVisible(false);
                    getWindow().showNotification(Lang.get("unable-to-add-attachment"), event.getFilename(),
                            Notification.TYPE_ERROR_MESSAGE);
                }

            });

            upload.addListener(new Upload.FinishedListener() {

                public void uploadFinished(FinishedEvent event) {

                    if (event.getLength() <= 0) {
                        getWindow().showNotification(Lang.get("unable-to-add-attachment"), event.getFilename(),
                                Notification.TYPE_ERROR_MESSAGE);
                        removeAttachment(AttachmentLayout.this);
                    } else {
                        size = event.getLength();
                        filename = event.getFilename();
                        setAttachment(event.getFilename(), event.getLength(), event.getMIMEType(), buffer);
                    }
                }

            });

        }

        public String getFilename() {

            return filename;
        }

        public boolean hasFile() {

            return size > 0;
        }

        public File getFile() {

            return buffer.getFile();
        }

        public long getSize() {

            return size;
        }

        public void delete() {

            buffer.delete();
        }

        private void setAttachment(String file, long length, String mime, Buffer buffer) {

            removeAllComponents();

            DecimalFormat df = new DecimalFormat("#########0.0");

            String size = null;
            if (length >= 1000 * 1000 * 1000) {
                size = df.format((float) length / (1000 * 1000 * 1000)) + " " + Lang.get("gigabytes");
            } else if (length >= 1000 * 1000) {
                size = df.format((float) length / (1000 * 1000)) + " " + Lang.get("megabytes");
            } else if (length >= 1000) {
                size = df.format((float) length / 1000) + " " + Lang.get("kilobytes");
            } else {
                size = df.format(length) + " " + Lang.get("bytes");
            }
            StreamResource sr = new StreamResource(buffer, file, getApplication());
            final Link l = new Link(file + " (" + size + ") ", sr);
            addComponent(l);

            Button b = new Button("x", new Button.ClickListener() {

                public void buttonClick(ClickEvent event) {

                    removeAttachment(AttachmentLayout.this);
                }
            });
            b.setDescription(Lang.get("remove") + file);
            b.setStyleName("small");
            addComponent(b);
            setExpandRatio(b, 1.0f);

        }

    }

    public class Buffer implements StreamResource.StreamSource, Upload.Receiver {

        String mimeType;

        String fileName;

        private File file;

        public Buffer() {

        }

        public InputStream getStream() {

            if (file == null) {
                return null;
            }
            try {
                return new FileInputStream(file);
            } catch (final FileNotFoundException e) {
                getWindow().showNotification(Lang.get("unable-to-add-attachment"), Notification.TYPE_ERROR_MESSAGE);
                _log.warn("Unable to attach files", e);
            }
            return null;
        }

        /**
         * @see com.vaadin.ui.Upload.Receiver#receiveUpload(String, String)
         */
        public OutputStream receiveUpload(String filename, String MIMEType) {

            fileName = filename;
            mimeType = MIMEType;

            if (file != null) {
                file.delete();
            }

            try {
                file = File.createTempFile("attachment", null);
            } catch (final IOException e) {
                getWindow().showNotification(Lang.get("unable-to-add-attachment"), filename,
                        Notification.TYPE_ERROR_MESSAGE);
                _log.warn("Unable to attach files", e);
            }

            try {
                return new FileOutputStream(file);
            } catch (final FileNotFoundException e) {
                getWindow().showNotification(Lang.get("unable-to-add-attachment"), filename,
                        Notification.TYPE_ERROR_MESSAGE);
                _log.warn("Unable to attach files", e);
            }
            return null;
        }

        /**
         * Returns the fileName.
         *
         * @return String
         */
        public String getFileName() {

            return fileName;
        }

        public File getFile() {

            return file;
        }

        /**
         * Returns the mimeType.
         *
         * @return String
         */
        public String getMimeType() {

            return mimeType;
        }

        public boolean delete() {

            if (file != null) {
                return file.delete();
            }
            // no file to delete - that's a success in our book
            return true;
        }

    }

    @Override
    protected void finalize() throws Throwable {

        for (AttachmentLayout attachment : attachments) {
            attachment.delete();
        }
    }

    public interface ComposerListener {

        public void messageDiscarded(Composer composer);

        public void messageSaved(Composer composer, Message message);

        public void messageSent(Composer composer, Message message);
    }

    public void focusToField() {
        toField.focus();
    }

    public void focusCCField() {
        ccField.focus();
    }

    public void focusBCCField() {
        bccField.focus();
    }

    public void focusSubject() {
        subject.focus();
    }

    public void focusBody() {
        message.focus();
    }

}