You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ClientModule.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * Copyright (c) 2006-2013 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc;
  23. import com.dmdirc.actions.ActionGroup;
  24. import com.dmdirc.actions.ActionManager;
  25. import com.dmdirc.actions.wrappers.AliasWrapper;
  26. import com.dmdirc.actions.wrappers.PerformWrapper;
  27. import com.dmdirc.commandline.CommandLineOptionsModule;
  28. import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
  29. import com.dmdirc.commandline.CommandLineOptionsModule.DirectoryType;
  30. import com.dmdirc.commandline.CommandLineParser;
  31. import com.dmdirc.commandparser.CommandLoader;
  32. import com.dmdirc.commandparser.CommandManager;
  33. import com.dmdirc.config.ConfigManager;
  34. import com.dmdirc.config.IdentityManager;
  35. import com.dmdirc.config.InvalidIdentityFileException;
  36. import com.dmdirc.interfaces.ActionController;
  37. import com.dmdirc.interfaces.CommandController;
  38. import com.dmdirc.interfaces.IdentityController;
  39. import com.dmdirc.interfaces.LifecycleController;
  40. import com.dmdirc.logger.ErrorLevel;
  41. import com.dmdirc.logger.Logger;
  42. import com.dmdirc.messages.MessageSinkManager;
  43. import com.dmdirc.plugins.PluginInfo;
  44. import com.dmdirc.plugins.PluginManager;
  45. import com.dmdirc.ui.WarningDialog;
  46. import com.dmdirc.ui.core.components.StatusBarManager;
  47. import com.dmdirc.ui.messages.ColourManager;
  48. import com.dmdirc.ui.themes.ThemeManager;
  49. import com.dmdirc.updater.UpdateChecker;
  50. import com.dmdirc.updater.Version;
  51. import com.dmdirc.updater.components.LauncherComponent;
  52. import com.dmdirc.updater.manager.UpdateManager;
  53. import java.awt.GraphicsEnvironment;
  54. import java.io.File;
  55. import java.text.SimpleDateFormat;
  56. import java.util.Date;
  57. import java.util.Set;
  58. import javax.inject.Provider;
  59. import javax.inject.Singleton;
  60. import dagger.Module;
  61. import dagger.Provides;
  62. /**
  63. * Provides dependencies for the client.
  64. */
  65. @Module(injects = {Main.class, CommandLineParser.class}, includes = CommandLineOptionsModule.class)
  66. public class ClientModule {
  67. /**
  68. * Provides an identity manager for the client.
  69. *
  70. * @param directory The directory to load settings from.
  71. * @param commandLineParser The CLI parser to read command line settings from.
  72. * @return An initialised {@link IdentityManager}.
  73. */
  74. @Provides
  75. @Singleton
  76. public IdentityManager getIdentityManager(
  77. @Directory(DirectoryType.BASE) final String directory,
  78. final CommandLineParser commandLineParser) {
  79. final IdentityManager identityManager = new IdentityManager(directory);
  80. IdentityManager.setIdentityManager(identityManager);
  81. identityManager.loadVersionIdentity();
  82. try {
  83. identityManager.initialise();
  84. } catch (InvalidIdentityFileException ex) {
  85. handleInvalidConfigFile(identityManager, directory);
  86. }
  87. if (commandLineParser.getDisableReporting()) {
  88. identityManager.getGlobalConfigIdentity()
  89. .setOption("temp", "noerrorreporting", true);
  90. }
  91. return identityManager;
  92. }
  93. /**
  94. * Provides an identity controller.
  95. *
  96. * @param manager The identity manager to use as a controller.
  97. * @return An identity controller to use.
  98. */
  99. @Provides
  100. public IdentityController getIdentityController(final IdentityManager manager) {
  101. return manager;
  102. }
  103. /**
  104. * Provides a parser factory.
  105. *
  106. * @param pluginManager The plugin manager to use to find parsers.
  107. * @return A parser factory for use in the client.
  108. */
  109. @Provides
  110. public ParserFactory getParserFactory(final PluginManager pluginManager) {
  111. return new ParserFactory(pluginManager);
  112. }
  113. /**
  114. * Provides an action manager.
  115. *
  116. * @param serverManager The server manager to use to iterate servers.
  117. * @param identityController The identity controller to use to look up settings.
  118. * @param aliasWrapperProvider Provider for {@link AliasWrapper}s.
  119. * @param performWrapperProvider Provider for {@link PerformWrapper}s.
  120. * @return An unitialised action manager.
  121. */
  122. @Provides
  123. @Singleton
  124. public ActionManager getActionManager(
  125. final ServerManager serverManager,
  126. final IdentityController identityController,
  127. final Provider<Set<ActionGroup>> actionWrappersProvider) {
  128. final ActionManager actionManager = new ActionManager(serverManager,
  129. identityController, actionWrappersProvider);
  130. ActionManager.setActionManager(actionManager);
  131. return actionManager;
  132. }
  133. /**
  134. * Provides an action controller.
  135. *
  136. * @param actionManager The action manager to use as a controller.
  137. * @return An action controller to use.
  138. */
  139. @Provides
  140. public ActionController getActionController(final ActionManager actionManager) {
  141. return actionManager;
  142. }
  143. /**
  144. * Provides a lifecycle controller.
  145. *
  146. * @param controller The concrete implementation to use.
  147. * @return The lifecycle controller the app should use.
  148. */
  149. @Provides
  150. public LifecycleController getLifecycleController(final SystemLifecycleController controller) {
  151. return controller;
  152. }
  153. /**
  154. * Provides a status bar manager.
  155. *
  156. * @return The status bar manager the client should use.
  157. */
  158. @Provides
  159. @Singleton
  160. public StatusBarManager getStatusBarManager() {
  161. final StatusBarManager manager = new StatusBarManager();
  162. StatusBarManager.setStatusBarManager(manager);
  163. return manager;
  164. }
  165. /**
  166. * Gets the message sink manager for the client.
  167. *
  168. * @param statusBarManager The status bar manager to use for status bar sinks.
  169. * @return The message sink manager the client should use.
  170. */
  171. @Provides
  172. @Singleton
  173. public MessageSinkManager getMessageSinkManager(final StatusBarManager statusBarManager) {
  174. final MessageSinkManager messageSinkManager = new MessageSinkManager();
  175. MessageSinkManager.setManager(messageSinkManager);
  176. messageSinkManager.loadDefaultSinks(statusBarManager);
  177. return messageSinkManager;
  178. }
  179. /**
  180. * Gets the command manager the client should use.
  181. *
  182. * @param serverManager The manager to use to iterate servers.
  183. * @param identityController The controller to use to read settings.
  184. * @param commandLoader The loader to use to populate default commands.
  185. * @return The command manager the client should use.
  186. */
  187. @Provides
  188. @Singleton
  189. public CommandManager getCommandManager(
  190. final ServerManager serverManager,
  191. final IdentityController identityController,
  192. final CommandLoader commandLoader) {
  193. final CommandManager manager = new CommandManager(serverManager);
  194. manager.initialise(identityController.getGlobalConfiguration());
  195. CommandManager.setCommandManager(manager);
  196. commandLoader.loadCommands(manager);
  197. return manager;
  198. }
  199. /**
  200. * Gets a command controller for use in the client.
  201. *
  202. * @param commandManager The manager to use as a controller.
  203. * @return The command controller the client should use.
  204. */
  205. @Provides
  206. public CommandController getCommandController(final CommandManager commandManager) {
  207. return commandManager;
  208. }
  209. /**
  210. * Gets an initialised plugin manager for the client.
  211. *
  212. * @param identityController The controller to read settings from.
  213. * @param actionController The action controller to use for events.
  214. * @param updateManager The update manager to inform about plugins.
  215. * @param directory The directory to load and save plugins in.
  216. * @return An initialised plugin manager for the client.
  217. */
  218. @Provides
  219. @Singleton
  220. public PluginManager getPluginManager(
  221. final IdentityController identityController,
  222. final ActionController actionController,
  223. final UpdateManager updateManager,
  224. @Directory(DirectoryType.PLUGINS) final String directory) {
  225. final PluginManager manager = new PluginManager(identityController, actionController, updateManager, directory);
  226. final CorePluginExtractor extractor = new CorePluginExtractor(manager, directory);
  227. checkBundledPlugins(extractor, manager, identityController.getGlobalConfiguration());
  228. for (String service : new String[]{"ui", "tabcompletion", "parser"}) {
  229. ensureExists(extractor, manager, service);
  230. }
  231. // The user may have an existing parser plugin (e.g. twitter) which
  232. // will satisfy the service existance check above, but will render the
  233. // client pretty useless, so we'll force IRC extraction for now.
  234. extractor.extractCorePlugins("parser_irc");
  235. manager.refreshPlugins();
  236. return manager;
  237. }
  238. /**
  239. * Gets a core plugin extractor.
  240. *
  241. * @param pluginManager The plugin manager to notify about updates.
  242. * @param directory The directory to extract plugins to.
  243. * @return A plugin extractor for the client to use.
  244. */
  245. @Provides
  246. public CorePluginExtractor getCorePluginExtractor(
  247. final PluginManager pluginManager,
  248. @Directory(DirectoryType.PLUGINS) final String directory) {
  249. return new CorePluginExtractor(pluginManager, directory);
  250. }
  251. /**
  252. * Gets an update manager for the client.
  253. *
  254. * @param commandLineParser CLI parser to use to find launcher version.
  255. * @return The update manager to use.
  256. */
  257. @Provides
  258. @Singleton
  259. public UpdateManager getUpdateManager(final CommandLineParser commandLineParser) {
  260. UpdateChecker.init();
  261. final UpdateManager manager = UpdateChecker.getManager();
  262. if (commandLineParser.getLauncherVersion() != null) {
  263. LauncherComponent.setLauncherInfo(manager, commandLineParser.getLauncherVersion());
  264. }
  265. return manager;
  266. }
  267. /**
  268. * Gets a theme manager for the client.
  269. *
  270. * @param controller The identity controller to use to access settings.
  271. * @param directory The directory to load themes from.
  272. * @return An initialised theme manager instance.
  273. */
  274. @Provides
  275. @Singleton
  276. public ThemeManager getThemeManager(
  277. final IdentityController controller,
  278. @Directory(DirectoryType.THEMES) final String directory) {
  279. final ThemeManager manager = new ThemeManager(controller, directory);
  280. ThemeManager.setThemeManager(manager);
  281. manager.refreshAndLoadThemes();
  282. return manager;
  283. }
  284. /**
  285. * Gets the alias actions wrapper.
  286. *
  287. * @param commandController The controller to register commands with
  288. * @param serverManager The manager to use to iterate servers.
  289. * @return An alias wrapper to use in the client.
  290. */
  291. @Provides(type = Provides.Type.SET)
  292. @Singleton
  293. public ActionGroup getAliasWrapper(
  294. final CommandController commandController,
  295. final ServerManager serverManager) {
  296. final AliasWrapper wrapper = new AliasWrapper(commandController, serverManager);
  297. AliasWrapper.setAliasWrapper(wrapper);
  298. return wrapper;
  299. }
  300. /**
  301. * Gets the performs actions wrapper.
  302. *
  303. * @return An performs wrapper to use in the client.
  304. */
  305. @Provides(type = Provides.Type.SET)
  306. @Singleton
  307. public ActionGroup getPerformWrapper() {
  308. final PerformWrapper wrapper = new PerformWrapper();
  309. PerformWrapper.setPerformWrapper(wrapper);
  310. return wrapper;
  311. }
  312. /**
  313. * Gets the colour manager.
  314. *
  315. * @param controller The identity controller to read settings from.
  316. * @return A colour manager for the client.
  317. */
  318. @Provides
  319. @Singleton
  320. public ColourManager getColourManager(final IdentityController controller) {
  321. final ColourManager manager = new ColourManager(controller.getGlobalConfiguration());
  322. ColourManager.setColourManager(manager);
  323. return manager;
  324. }
  325. /**
  326. * Called when the global config cannot be loaded due to an error. This
  327. * method informs the user of the problem and installs a new default config
  328. * file, backing up the old one.
  329. *
  330. * @param identityManager The identity manager to re-initialise after installing defaults.
  331. * @param configdir The directory to extract default settings into.
  332. */
  333. private void handleInvalidConfigFile(final IdentityManager identityManager, final String configdir) {
  334. final String date = new SimpleDateFormat("yyyyMMddkkmmss").format(new Date());
  335. final String message = "DMDirc has detected that your config file "
  336. + "has become corrupted.<br><br>DMDirc will now backup "
  337. + "your current config and try restarting with a default "
  338. + "config.<br><br>Your old config will be saved as:<br>"
  339. + "dmdirc.config." + date;
  340. if (!GraphicsEnvironment.isHeadless()) {
  341. new WarningDialog("Invalid Config File", message).displayBlocking();
  342. }
  343. // Let command-line users know what is happening.
  344. System.out.println(message.replace("<br>", "\n"));
  345. final File configFile = new File(configdir + "dmdirc.config");
  346. final File newConfigFile = new File(configdir + "dmdirc.config." + date);
  347. if (configFile.renameTo(newConfigFile)) {
  348. try {
  349. identityManager.initialise();
  350. } catch (InvalidIdentityFileException iife) {
  351. // This shouldn't happen!
  352. Logger.appError(ErrorLevel.FATAL, "Unable to load global config", iife);
  353. }
  354. } else {
  355. final String newMessage = "DMDirc was unable to rename the "
  356. + "global config file and is unable to fix this issue.";
  357. if (!GraphicsEnvironment.isHeadless()) {
  358. new WarningDialog("Invalid Config File", newMessage).displayBlocking();
  359. }
  360. System.out.println(newMessage.replace("<br>", "\n"));
  361. System.exit(1);
  362. }
  363. }
  364. /**
  365. * Ensures that there is at least one provider of the specified
  366. * service type by extracting matching core plugins. Plugins must be named
  367. * so that their file name starts with the service type, and then an
  368. * underscore.
  369. *
  370. * @param corePluginExtractor Extractor to use if the service doesn't exist
  371. * @param pm The plugin manager to use to access services
  372. * @param serviceType The type of service that should exist
  373. */
  374. public void ensureExists(
  375. final CorePluginExtractor corePluginExtractor,
  376. final PluginManager pm,
  377. final String serviceType) {
  378. if (pm.getServicesByType(serviceType).isEmpty()) {
  379. corePluginExtractor.extractCorePlugins(serviceType + "_");
  380. pm.refreshPlugins();
  381. }
  382. }
  383. /**
  384. * Checks whether the plugins bundled with this release of DMDirc are newer
  385. * than the plugins known by the specified {@link PluginManager}. If the
  386. * bundled plugins are newer, they are automatically extracted.
  387. *
  388. * @param corePluginExtractor Extractor to use if plugins need updating.
  389. * @param pm The plugin manager to use to check plugins
  390. * @param config The configuration source for bundled versions
  391. */
  392. private void checkBundledPlugins(
  393. final CorePluginExtractor corePluginExtractor,
  394. final PluginManager pm,
  395. final ConfigManager config) {
  396. for (PluginInfo plugin : pm.getPluginInfos()) {
  397. if (config.hasOptionString("bundledplugins_versions", plugin.getMetaData().getName())) {
  398. final Version bundled = new Version(config.getOption("bundledplugins_versions",
  399. plugin.getMetaData().getName()));
  400. final Version installed = plugin.getMetaData().getVersion();
  401. if (installed.compareTo(bundled) < 0) {
  402. corePluginExtractor.extractCorePlugins(plugin.getMetaData().getName());
  403. pm.reloadPlugin(plugin.getFilename());
  404. }
  405. }
  406. }
  407. }
  408. }