~chipaca/ubuntuone-windows-installer/miscelanea

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * Copyright 2010 Canonical Ltd.
 * 
 * This file is part of Ubuntu One on Windows.
 * 
 * UbuntuOne on Windows is free software: you can redistribute it and/or modify		
 * it under the terms of the GNU Lesser General Public License version 		
 * as published by the Free Software Foundation.		
 *		
 * Ubuntu One on Windows 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.	
 *
 * You should have received a copy of the GNU Lesser General Public License	
 * along with UbuntuOne for Windows.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
 */
using System;
using System.Security.Principal;
using System.Threading;
using System.Windows;
using Canonical.UbuntuOne.Client.Notification;
using Canonical.UbuntuOne.Client.Preferences;
using Canonical.UbuntuOne.Common.Container;
using Canonical.UbuntuOne.Common.Update;
using Canonical.UbuntuOne.Common.Utils;
using Canonical.UbuntuOne.ProcessDispatcher;
using log4net;

namespace UbuntuOneClient
{
    /// <summary>
    /// Class that will start the application when needed.
    /// </summary>
    internal class Program
    {
        private static readonly ILog _logger = LogManager.GetLogger(typeof(Program));
        private IUpdater _updater;
        private readonly object _updaterLock = new object();
        private INotificationIconView _notifyIcon;
        private readonly object _notifyIconLock = new object();
        private Thread _updatesThread;
        private static readonly ConfigurationLocator _configLocator = new ConfigurationLocator();

        #region DI Properties for testability

        /// <summary>
        /// Allows to get and set the updater to be used, if the updater is not present the class
        /// will use the ObjectsContainer to retrieve it. This property has been added to increase the testability
        /// of the class.
        /// </summary>
        internal IUpdater Updater
        {
            get
            {
                if (_updater == null)
                {
                    lock (_updaterLock)
                    {
                        _updater = ObjectsContainer.GetImplementationOf<IUpdater>();
                    }
                }
                return _updater;
            }
            set { _updater = value; }
        }

        /// <summary>
        /// Allows to get and set the notification icon, if the notification icon is not present the class 
        /// will use the Objects container to retrieve it. This property has been added to icrease the testability of the 
        /// class.
        /// </summary>
        internal INotificationIconView NotifyIcon
        {
            get
            {
                if (_notifyIcon == null)
                {
                    lock (_notifyIconLock)
                    {
                        _notifyIcon = ObjectsContainer.GetImplementationOf<INotificationIconView>();
                    }
                }
                return _notifyIcon;
            }
            set { _notifyIcon = value; }
        }

        /// <summary>
        /// Allows to get and set the application that will be used to ran the client. This property has been 
        /// added to increase the testability of the class.
        /// </summary>
        internal IApplication Application { get; set; }

        /// <summary>
        /// Allows to get and set the presenter that knows how to deal with the settings.
        /// </summary>
        internal IPreferencesDialogPresenter PreferencesDialogPresenter { get; set; }

        /// <summary>
        /// Gets and sets the listener that will be used to listen to messages from the python code.
        /// </summary>
        internal IPipeListener PipeListener { get; set; }

        #endregion

        #region Helper methods

        /// <summary>
        /// Helper method that will check for updates and will ask the user if an update is required.
        /// </summary>
        private void CheckForUpdates()
        {
            try
            {
                if (!Updater.UpdatesArePresent()) return;
                _logger.Info("Updates are available.");
                Updater.PerformUpdate();
            }
            catch (SelfUpdateException ex)
            {
                _logger.WarnFormat("Application could not be update {0}", ex);
            }
        }

        #endregion

        /// <summary>
        /// Starts the application when requested. The code has been refactored to this method to allow
        /// unit testing.
        /// </summary>
        public void StartApplication()
        {
            _logger.Debug("Starting client application.");
            // we explicitly want to stop the application
            Application.ShutdownMode = ShutdownMode.OnExplicitShutdown;
            // we start the check for updates in another thread so that we do not block the user, 
            // that way we will not stop the execution of the application while we chec the rss feed.
            _updatesThread = new Thread(CheckForUpdates);
            _updatesThread.Start();
            // we are goign to load the current settings
            // TODO: using the presenter here is very ugly.
            PreferencesDialogPresenter.LoadPreferences();
            PipeListener.StartListening(string.Format("PythonMessages{0}", WindowsIdentity.GetCurrent().Name));
            // we do not worry about looping to allow the other thread to finish, we no that app should take longer
            Application.Run(NotifyIcon as Window);
            
        }

        /// <summary>
        /// Allows to stop the trhad that is checking if updates are avialble.
        /// </summary>
        public void StopUpdaterThread()
        {
            if (_updatesThread != null)
            {
                _updatesThread.Join();
            }
            else
            {
                _logger.Warn("Not update thread exists.");
            }
        }


        [STAThread]
        static void Main()
        {
            _logger.Info("Updating config");
            // init the objects container
            // Setup information for the new appdomain.

            ObjectsContainer.Initialize(new SpringContainer());
            var program = ObjectsContainer.GetImplementationOf<Program>();
            program.StartApplication();

        }
    }

}