001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.operations.daemon;
019
020import java.util.logging.Level;
021import java.util.logging.Logger;
022
023import org.syncany.config.LocalEventBus;
024import org.syncany.operations.daemon.messages.ConfirmUserInteractionExternalEvent;
025import org.syncany.operations.daemon.messages.ConfirmUserInteractionExternalEventResponse;
026import org.syncany.operations.daemon.messages.GetPasswordUserInteractionExternalEvent;
027import org.syncany.operations.daemon.messages.GetPasswordUserInteractionExternalEventResponse;
028import org.syncany.plugins.UserInteractionListener;
029
030import com.google.common.eventbus.Subscribe;
031
032/**
033 * This implementation of a {@link UserInteractionListener} uses the {@link LocalEventBus}
034 * to broadcast interaction requests to subscribers and waits synchronously for a corresponding
035 * event response. All methods wait until the response event arrives by sending the current
036 * thread to sleep via {@link #wait()}, and waking it up via {@link #notify()}.  
037 * 
038 * @see UserInteractionListener
039 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
040 */
041public class EventUserInteractionListener implements UserInteractionListener {
042        private static final Logger logger = Logger.getLogger(EventUserInteractionListener.class.getSimpleName());
043
044        private LocalEventBus eventBus;
045        private Object waitObject;
046        private Object userResponse;
047        
048        public EventUserInteractionListener() {
049                this.eventBus = LocalEventBus.getInstance();
050                this.eventBus.register(this);
051                this.waitObject = new Object();
052        }
053        
054        @Override
055        public boolean onUserConfirm(String header, String message, String question) {
056                logger.log(Level.INFO, "User confirmation needed for '" + header + "'. Sending message.");
057                eventBus.post(new ConfirmUserInteractionExternalEvent(header, message, question));
058                
059                ConfirmUserInteractionExternalEventResponse userConfirmation = (ConfirmUserInteractionExternalEventResponse) waitForUserResponse();
060                return userConfirmation.getResult();
061        }
062
063        @Override
064        public String onUserPassword(String header, String message) {
065                logger.log(Level.INFO, "User password needed. Sending message.");
066                eventBus.post(new GetPasswordUserInteractionExternalEvent());
067                
068                GetPasswordUserInteractionExternalEventResponse userConfirmation = (GetPasswordUserInteractionExternalEventResponse) waitForUserResponse();
069                return userConfirmation.getPassword();
070        }
071
072        @Override
073        public String onUserNewPassword() {
074                throw new RuntimeException("onUserNewPassword() not implemented for WebSocket init/connect.");
075        }               
076        
077        @Subscribe
078        public void onConfirmUserInteractionExternalManagementRequest(ConfirmUserInteractionExternalEventResponse response) {
079                userResponse = response;                
080                fireUserResponseReady();                        
081        }
082        
083        @Subscribe
084        public void onGetPasswordUserInteractionExternalManagementRequest(GetPasswordUserInteractionExternalEventResponse response) {
085                userResponse = response;                
086                fireUserResponseReady();                        
087        }
088        
089        private Object waitForUserResponse() {
090                try {
091                        synchronized (waitObject) {
092                                waitObject.wait();      
093                        }
094                        
095                        return userResponse;
096                }
097                catch (InterruptedException e) {
098                        logger.log(Level.SEVERE, "User interaction listener interrupted.", e);
099                        return null;
100                }
101        }
102        
103        private void fireUserResponseReady() {
104                synchronized (waitObject) {
105                        waitObject.notify();    
106                }
107        }
108}