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.

IdentityManager.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. /*
  2. * Copyright (c) 2006-2014 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.config;
  23. import com.dmdirc.Precondition;
  24. import com.dmdirc.events.UserErrorEvent;
  25. import com.dmdirc.interfaces.config.AggregateConfigProvider;
  26. import com.dmdirc.interfaces.config.ConfigProvider;
  27. import com.dmdirc.interfaces.config.ConfigProviderListener;
  28. import com.dmdirc.interfaces.config.ConfigProviderMigrator;
  29. import com.dmdirc.interfaces.config.IdentityController;
  30. import com.dmdirc.interfaces.config.IdentityFactory;
  31. import com.dmdirc.logger.ErrorLevel;
  32. import com.dmdirc.updater.Version;
  33. import com.dmdirc.util.collections.MapList;
  34. import com.dmdirc.util.collections.WeakMapList;
  35. import com.dmdirc.util.io.ConfigFile;
  36. import com.dmdirc.util.io.InvalidConfigFileException;
  37. import com.dmdirc.util.resourcemanager.ResourceManager;
  38. import net.engio.mbassy.bus.MBassador;
  39. import java.io.File;
  40. import java.io.IOException;
  41. import java.util.ArrayList;
  42. import java.util.Collections;
  43. import java.util.HashMap;
  44. import java.util.LinkedHashSet;
  45. import java.util.List;
  46. import java.util.Map;
  47. import java.util.Set;
  48. import org.slf4j.LoggerFactory;
  49. import static com.google.common.base.Preconditions.checkArgument;
  50. import static com.google.common.base.Preconditions.checkNotNull;
  51. public class IdentityManager implements IdentityFactory, IdentityController {
  52. private static final org.slf4j.Logger log = LoggerFactory.getLogger(IdentityManager.class);
  53. /** A regular expression that will match all characters illegal in file names. */
  54. private static final String ILLEGAL_CHARS = "[\\\\\"/:\\*\\?\"<>\\|]";
  55. /** The domain used for identity settings. */
  56. private static final String IDENTITY_DOMAIN = "identity";
  57. /** The domain used for profile settings. */
  58. private static final String PROFILE_DOMAIN = "profile";
  59. /** Base configuration directory where the main configuration file will be located. */
  60. private final String configDirectory;
  61. /** Directory to save and load identities in. */
  62. private final String identitiesDirectory;
  63. /**
  64. * The identities that have been loaded into this manager.
  65. *
  66. * Standard identities are inserted with a <code>null</code> key, custom identities use their
  67. * custom type as the key.
  68. */
  69. private final MapList<String, ConfigProvider> identities = new MapList<>();
  70. /** The event bus to post events to. */
  71. private final MBassador eventBus;
  72. /**
  73. * The {@link IdentityListener}s that have registered with this manager.
  74. *
  75. * Listeners for standard identities are inserted with a <code>null</code> key, listeners for a
  76. * specific custom type use their type as the key.
  77. */
  78. private final MapList<String, ConfigProviderListener> listeners = new WeakMapList<>();
  79. /** The identity file used for the global config. */
  80. private ConfigProvider config;
  81. /** The identity file used for addon defaults. */
  82. private ConfigProvider addonConfig;
  83. /** The identity file bundled with the client containing version info. */
  84. private ConfigProvider versionConfig;
  85. /** The config manager used for global settings. */
  86. private AggregateConfigProvider globalconfig;
  87. /**
  88. * Creates a new instance of IdentityManager.
  89. *
  90. * @param baseDirectory The BASE config directory.
  91. * @param identitiesDirectory The directory to store identities in.
  92. * @param eventBus The event bus to post events to
  93. */
  94. public IdentityManager(final String baseDirectory, final String identitiesDirectory,
  95. final MBassador eventBus) {
  96. this.configDirectory = baseDirectory;
  97. this.identitiesDirectory = identitiesDirectory;
  98. this.eventBus = eventBus;
  99. }
  100. /**
  101. * Loads all identity files.
  102. *
  103. * @throws InvalidIdentityFileException If there is an error with the config file.
  104. */
  105. public void initialise() throws InvalidIdentityFileException {
  106. identities.clear();
  107. loadVersionIdentity();
  108. loadDefaults();
  109. loadUserIdentities();
  110. loadConfig();
  111. if (getProvidersByType("profile").isEmpty()) {
  112. createProfileConfig("Default Profile");
  113. }
  114. // Set up the identity used for the addons defaults
  115. final ConfigTarget target = new ConfigTarget();
  116. target.setGlobalDefault();
  117. target.setOrder(500000);
  118. final ConfigFile addonConfigFile = new ConfigFile((File) null);
  119. final Map<String, String> addonSettings = new HashMap<>();
  120. addonSettings.put("name", "Addon defaults");
  121. addonConfigFile.addDomain("identity", addonSettings);
  122. addonConfig = new ConfigFileBackedConfigProvider(this, addonConfigFile, target);
  123. addConfigProvider(addonConfig);
  124. if (!getGlobalConfiguration().hasOptionString("identity", "defaultsversion")) {
  125. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.FATAL, null,
  126. "Default settings could not be loaded", ""));
  127. }
  128. }
  129. /** Loads the default (built in) identities. */
  130. private void loadDefaults() {
  131. final String[] targets = {"default", "modealiases"};
  132. for (String target : targets) {
  133. final File file = new File(identitiesDirectory + target);
  134. if (file.exists() && !file.isDirectory()) {
  135. boolean success = false;
  136. for (int i = 0; i < 10 && !success; i++) {
  137. final String suffix = ".old" + (i > 0 ? "-" + i : "");
  138. success = file.renameTo(new File(file.getParentFile(), target + suffix));
  139. }
  140. if (!success) {
  141. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.HIGH, null,
  142. "Unable to create directory for default settings folder ("
  143. + target + ")",
  144. "A file with that name already exists, and couldn't be renamed."
  145. + " Rename or delete " + file.getAbsolutePath()));
  146. continue;
  147. }
  148. }
  149. if (!file.exists() && !file.mkdirs()) {
  150. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.FATAL, null,
  151. "Unable to create required directory '" + file.getAbsolutePath()
  152. + "'. Please check file permissions or specify "
  153. + "a different configuration directory.", ""));
  154. return;
  155. }
  156. if (file.listFiles() == null || file.listFiles().length == 0) {
  157. extractIdentities(target);
  158. }
  159. loadUser(file);
  160. }
  161. extractFormatters();
  162. // If the bundled defaults are newer than the ones the user is
  163. // currently using, extract them.
  164. if (getGlobalConfiguration().hasOptionString("identity", "defaultsversion")
  165. && getGlobalConfiguration().hasOptionString("updater", "bundleddefaultsversion")) {
  166. final Version installedVersion = new Version(getGlobalConfiguration()
  167. .getOption("identity", "defaultsversion"));
  168. final Version bundledVersion = new Version(getGlobalConfiguration()
  169. .getOption("updater", "bundleddefaultsversion"));
  170. if (bundledVersion.compareTo(installedVersion) > 0) {
  171. extractIdentities("default");
  172. loadUser(new File(identitiesDirectory, "default"));
  173. }
  174. }
  175. }
  176. /**
  177. * Extracts the bundled formatters to the user's identity folder.
  178. */
  179. private void extractFormatters() {
  180. try {
  181. ResourceManager.getResourceManager().extractResource(
  182. "com/dmdirc/config/defaults/default/formatter",
  183. identitiesDirectory + "default/", false);
  184. } catch (IOException ex) {
  185. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, null,
  186. "Unable to extract default formatters: " + ex.getMessage(), ""));
  187. }
  188. }
  189. /**
  190. * Extracts the specific set of default identities to the user's identity folder.
  191. *
  192. * @param target The target to be extracted
  193. */
  194. private void extractIdentities(final String target) {
  195. try {
  196. ResourceManager.getResourceManager().extractResources(
  197. "com/dmdirc/config/defaults/" + target,
  198. identitiesDirectory + target, false);
  199. } catch (IOException ex) {
  200. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, null,
  201. "Unable to extract default identities: " + ex.getMessage(), ""));
  202. }
  203. }
  204. @Override
  205. public void loadUserIdentities() {
  206. final File dir = new File(identitiesDirectory);
  207. if (!dir.exists()) {
  208. try {
  209. dir.mkdirs();
  210. dir.createNewFile();
  211. } catch (IOException ex) {
  212. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, ex,
  213. "Unable to create identity dir", ""));
  214. }
  215. }
  216. loadUser(dir);
  217. }
  218. /**
  219. * Recursively loads files from the specified directory.
  220. *
  221. * @param dir The directory to be loaded
  222. */
  223. @Precondition({
  224. "The specified File is not null",
  225. "The specified File is a directory"
  226. })
  227. private void loadUser(final File dir) {
  228. checkNotNull(dir);
  229. checkArgument(dir.isDirectory());
  230. if (dir.listFiles() == null) {
  231. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, null,
  232. "Unable to load user identity files from " + dir.getAbsolutePath(), ""));
  233. } else {
  234. for (File file : dir.listFiles()) {
  235. if (file.isDirectory()) {
  236. loadUser(file);
  237. } else {
  238. loadIdentity(file);
  239. }
  240. }
  241. }
  242. }
  243. /**
  244. * Loads an identity from the specified file. If the identity already exists, it is told to
  245. * reload instead.
  246. *
  247. * @param file The file to load the identity from.
  248. */
  249. private void loadIdentity(final File file) {
  250. synchronized (identities) {
  251. for (ConfigProvider identity : getAllIdentities()) {
  252. if ((identity instanceof ConfigFileBackedConfigProvider)
  253. && ((ConfigFileBackedConfigProvider) identity).isFile(file)) {
  254. // TODO: This manager should keep a list of files->identities instead of
  255. // relying on the identities remembering.
  256. try {
  257. identity.reload();
  258. } catch (IOException ex) {
  259. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, null,
  260. "I/O error when reloading identity file: "
  261. + file.getAbsolutePath() + " (" + ex.getMessage() + ")", ""));
  262. } catch (InvalidConfigFileException ex) {
  263. // Do nothing
  264. }
  265. return;
  266. }
  267. }
  268. }
  269. try {
  270. addConfigProvider(new ConfigFileBackedConfigProvider(this, file, false));
  271. } catch (InvalidIdentityFileException ex) {
  272. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, null,
  273. "Invalid identity file: " + file.getAbsolutePath() + " ("
  274. + ex.getMessage() + ")", ""));
  275. } catch (IOException ex) {
  276. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, null,
  277. "I/O error when reading identity file: " + file.getAbsolutePath(), ""));
  278. }
  279. }
  280. /**
  281. * Retrieves all known identities.
  282. *
  283. * @return A set of all known identities
  284. *
  285. * @since 0.6.4
  286. */
  287. private Set<ConfigProvider> getAllIdentities() {
  288. final Set<ConfigProvider> res = new LinkedHashSet<>();
  289. for (Map.Entry<String, List<ConfigProvider>> entry : identities.entrySet()) {
  290. res.addAll(entry.getValue());
  291. }
  292. return res;
  293. }
  294. /**
  295. * Returns the "group" to which the specified identity belongs. For custom identities this is
  296. * the custom identity type, otherwise this is <code>null</code>.
  297. *
  298. * @param identity The identity whose group is being retrieved
  299. *
  300. * @return The group of the specified identity
  301. *
  302. * @since 0.6.4
  303. */
  304. private String getGroup(final ConfigProvider identity) {
  305. return identity.getTarget().getType() == ConfigTarget.TYPE.CUSTOM
  306. ? identity.getTarget().getData() : null;
  307. }
  308. @Override
  309. public void loadVersionIdentity() {
  310. try {
  311. versionConfig = new ConfigFileBackedConfigProvider(IdentityManager.class.
  312. getResourceAsStream("/com/dmdirc/version.config"), false);
  313. addConfigProvider(versionConfig);
  314. } catch (IOException | InvalidIdentityFileException ex) {
  315. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, ex,
  316. "Unable to load version information", ""));
  317. }
  318. }
  319. /**
  320. * Loads the config identity.
  321. *
  322. * @throws InvalidIdentityFileException if there is a problem with the config file.
  323. */
  324. private void loadConfig() throws InvalidIdentityFileException {
  325. try {
  326. final File file = new File(configDirectory + "dmdirc.config");
  327. if (!file.exists()) {
  328. file.createNewFile();
  329. }
  330. config = new ConfigFileBackedConfigProvider(this, file, true);
  331. config.setOption("identity", "name", "Global config");
  332. addConfigProvider(config);
  333. } catch (IOException ex) {
  334. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, ex,
  335. "I/O error when loading global config: " + ex.getMessage(), ""));
  336. }
  337. }
  338. @Override
  339. public ConfigProvider getUserSettings() {
  340. return config;
  341. }
  342. @Override
  343. public ConfigProvider getAddonSettings() {
  344. return addonConfig;
  345. }
  346. @Override
  347. public ConfigProvider getVersionSettings() {
  348. return versionConfig;
  349. }
  350. @Override
  351. public void saveAll() {
  352. synchronized (identities) {
  353. for (ConfigProvider identity : getAllIdentities()) {
  354. identity.save();
  355. }
  356. }
  357. }
  358. @Override
  359. public void addConfigProvider(final ConfigProvider identity) {
  360. checkNotNull(identity);
  361. final String target = getGroup(identity);
  362. if (identities.containsValue(target, identity)) {
  363. removeConfigProvider(identity);
  364. }
  365. synchronized (identities) {
  366. identities.add(target, identity);
  367. }
  368. log.debug("Adding identity: {} (group: {})",
  369. new Object[]{identity, target});
  370. synchronized (listeners) {
  371. for (ConfigProviderListener listener : listeners.safeGet(target)) {
  372. listener.configProviderAdded(identity);
  373. }
  374. }
  375. }
  376. @Override
  377. public void removeConfigProvider(final ConfigProvider identity) {
  378. checkNotNull(identity);
  379. final String group = getGroup(identity);
  380. checkArgument(identities.containsValue(group, identity));
  381. synchronized (identities) {
  382. identities.remove(group, identity);
  383. }
  384. synchronized (listeners) {
  385. for (ConfigProviderListener listener : listeners.safeGet(group)) {
  386. listener.configProviderRemoved(identity);
  387. }
  388. }
  389. }
  390. @Override
  391. public void registerIdentityListener(final ConfigProviderListener listener) {
  392. registerIdentityListener(null, listener);
  393. }
  394. @Override
  395. public void unregisterIdentityListener(final ConfigProviderListener listener) {
  396. listeners.removeFromAll(listener);
  397. }
  398. @Override
  399. public void registerIdentityListener(final String type, final ConfigProviderListener listener) {
  400. checkNotNull(listener);
  401. synchronized (listeners) {
  402. listeners.add(type, listener);
  403. }
  404. }
  405. @Override
  406. public List<ConfigProvider> getProvidersByType(final String type) {
  407. return Collections.unmodifiableList(identities.safeGet(type));
  408. }
  409. /**
  410. * Retrieves a list of all config sources that should be applied to the specified config
  411. * manager.
  412. *
  413. * @param manager The manager requesting sources
  414. *
  415. * @return A list of all matching config sources
  416. */
  417. List<ConfigProvider> getIdentitiesForManager(final ConfigManager manager) {
  418. final List<ConfigProvider> sources = new ArrayList<>();
  419. synchronized (identities) {
  420. for (ConfigProvider identity : identities.safeGet(null)) {
  421. if (manager.identityApplies(identity)) {
  422. sources.add(identity);
  423. }
  424. }
  425. }
  426. Collections.sort(sources, new ConfigProviderTargetComparator());
  427. log.debug("Found {} source(s) for {}", sources.size(), manager);
  428. return sources;
  429. }
  430. @Override
  431. public synchronized AggregateConfigProvider getGlobalConfiguration() {
  432. if (globalconfig == null) {
  433. globalconfig = createAggregateConfig("", "", "", "");
  434. }
  435. return globalconfig;
  436. }
  437. @Override
  438. public ConfigProvider createChannelConfig(final String network, final String channel) {
  439. if (network == null || network.isEmpty()) {
  440. throw new IllegalArgumentException("getChannelConfig called "
  441. + "with null or empty network\n\nNetwork: " + network);
  442. }
  443. if (channel == null || channel.isEmpty()) {
  444. throw new IllegalArgumentException("getChannelConfig called "
  445. + "with null or empty channel\n\nChannel: " + channel);
  446. }
  447. final String myTarget = (channel + "@" + network).toLowerCase();
  448. synchronized (identities) {
  449. for (ConfigProvider identity : identities.safeGet(null)) {
  450. if (identity.getTarget().getType() == ConfigTarget.TYPE.CHANNEL
  451. && identity.getTarget().getData().equalsIgnoreCase(myTarget)) {
  452. return identity;
  453. }
  454. }
  455. }
  456. // We need to create one
  457. final ConfigTarget target = new ConfigTarget();
  458. target.setChannel(myTarget);
  459. return createConfig(target);
  460. }
  461. @Override
  462. public ConfigProvider createNetworkConfig(final String network) {
  463. if (network == null || network.isEmpty()) {
  464. throw new IllegalArgumentException("getNetworkConfig called "
  465. + "with null or empty network\n\nNetwork:" + network);
  466. }
  467. final String myTarget = network.toLowerCase();
  468. synchronized (identities) {
  469. for (ConfigProvider identity : identities.safeGet(null)) {
  470. if (identity.getTarget().getType() == ConfigTarget.TYPE.NETWORK
  471. && identity.getTarget().getData().equalsIgnoreCase(myTarget)) {
  472. return identity;
  473. }
  474. }
  475. }
  476. // We need to create one
  477. final ConfigTarget target = new ConfigTarget();
  478. target.setNetwork(myTarget);
  479. return createConfig(target);
  480. }
  481. @Override
  482. public ConfigProvider createServerConfig(final String server) {
  483. if (server == null || server.isEmpty()) {
  484. throw new IllegalArgumentException("getServerConfig called "
  485. + "with null or empty server\n\nServer: " + server);
  486. }
  487. final String myTarget = server.toLowerCase();
  488. synchronized (identities) {
  489. for (ConfigProvider identity : identities.safeGet(null)) {
  490. if (identity.getTarget().getType() == ConfigTarget.TYPE.SERVER
  491. && identity.getTarget().getData().equalsIgnoreCase(myTarget)) {
  492. return identity;
  493. }
  494. }
  495. }
  496. // We need to create one
  497. final ConfigTarget target = new ConfigTarget();
  498. target.setServer(myTarget);
  499. return createConfig(target);
  500. }
  501. @Override
  502. public ConfigProvider createCustomConfig(final String name, final String type) {
  503. final Map<String, Map<String, String>> settings = new HashMap<>();
  504. settings.put(IDENTITY_DOMAIN, new HashMap<String, String>(2));
  505. settings.get(IDENTITY_DOMAIN).put("name", name);
  506. settings.get(IDENTITY_DOMAIN).put("type", type);
  507. try {
  508. return createIdentity(settings);
  509. } catch (InvalidIdentityFileException | IOException ex) {
  510. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, ex,
  511. "Unable to create identity", ""));
  512. return null;
  513. }
  514. }
  515. @Override
  516. public ConfigProvider createProfileConfig(final String name) {
  517. final Map<String, Map<String, String>> settings = new HashMap<>();
  518. settings.put(IDENTITY_DOMAIN, new HashMap<String, String>(1));
  519. settings.put(PROFILE_DOMAIN, new HashMap<String, String>(2));
  520. final String nick = System.getProperty("user.name").replace(' ', '_');
  521. settings.get(IDENTITY_DOMAIN).put("name", name);
  522. settings.get(PROFILE_DOMAIN).put("nicknames", nick);
  523. settings.get(PROFILE_DOMAIN).put("realname", nick);
  524. try {
  525. return createIdentity(settings);
  526. } catch (InvalidIdentityFileException | IOException ex) {
  527. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, ex,
  528. "Unable to create identity", ""));
  529. return null;
  530. }
  531. }
  532. @Override
  533. public ConfigProvider createConfig(final ConfigTarget target) {
  534. final Map<String, Map<String, String>> settings = new HashMap<>();
  535. settings.put(IDENTITY_DOMAIN, new HashMap<String, String>(2));
  536. settings.get(IDENTITY_DOMAIN).put("name", target.getData());
  537. settings.get(IDENTITY_DOMAIN).put(target.getTypeName(), target.getData());
  538. try {
  539. return createIdentity(settings);
  540. } catch (InvalidIdentityFileException | IOException ex) {
  541. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.MEDIUM, ex,
  542. "Unable to create identity", ""));
  543. return null;
  544. }
  545. }
  546. /**
  547. * Creates a new identity containing the specified properties.
  548. *
  549. * @param settings The settings to populate the identity with
  550. *
  551. * @return A new identity containing the specified properties
  552. *
  553. * @throws IOException If the file cannot be created
  554. * @throws InvalidIdentityFileException If the settings are invalid
  555. * @since 0.6.3m1
  556. */
  557. protected ConfigFileBackedConfigProvider createIdentity(
  558. final Map<String, Map<String, String>> settings)
  559. throws IOException, InvalidIdentityFileException {
  560. if (!settings.containsKey(IDENTITY_DOMAIN)
  561. || !settings.get(IDENTITY_DOMAIN).containsKey("name")
  562. || settings.get(IDENTITY_DOMAIN).get("name").isEmpty()) {
  563. throw new InvalidIdentityFileException("identity.name is not set");
  564. }
  565. final String name = settings.get(IDENTITY_DOMAIN).get("name").replaceAll(ILLEGAL_CHARS, "_");
  566. File file = new File(identitiesDirectory + name);
  567. int attempt = 1;
  568. while (file.exists()) {
  569. file = new File(identitiesDirectory + name + "-" + attempt);
  570. attempt++;
  571. }
  572. final ConfigFile configFile = new ConfigFile(file);
  573. for (Map.Entry<String, Map<String, String>> entry : settings.entrySet()) {
  574. configFile.addDomain(entry.getKey(), entry.getValue());
  575. }
  576. configFile.write();
  577. final ConfigFileBackedConfigProvider identity = new ConfigFileBackedConfigProvider(this,
  578. file, false);
  579. addConfigProvider(identity);
  580. return identity;
  581. }
  582. /**
  583. * Finds and adds sources for the given manager, and adds it as an identity listener.
  584. *
  585. * @param configManager The manager to be initialised.
  586. */
  587. private void setUpConfigManager(final ConfigManager configManager) {
  588. List<ConfigProvider> sources = getIdentitiesForManager(configManager);
  589. for (ConfigProvider identity : sources) {
  590. log.trace("Found {}", identity);
  591. configManager.checkIdentity(identity);
  592. }
  593. registerIdentityListener(configManager);
  594. }
  595. @Override
  596. public ConfigProviderMigrator createMigratableConfig(final String protocol,
  597. final String ircd, final String network, final String server) {
  598. final ConfigManager configManager = new ConfigManager(this, protocol, ircd, network, server);
  599. setUpConfigManager(configManager);
  600. return new ConfigManagerMigrator(configManager);
  601. }
  602. @Override
  603. public ConfigProviderMigrator createMigratableConfig(final String protocol,
  604. final String ircd, final String network, final String server, final String channel) {
  605. final ConfigManager configManager = new ConfigManager(this, protocol, ircd, network, server,
  606. channel);
  607. setUpConfigManager(configManager);
  608. return new ConfigManagerMigrator(configManager);
  609. }
  610. @Override
  611. public AggregateConfigProvider createAggregateConfig(final String protocol, final String ircd,
  612. final String network, final String server) {
  613. final ConfigManager configManager = new ConfigManager(this, protocol, ircd, network, server);
  614. setUpConfigManager(configManager);
  615. return configManager;
  616. }
  617. @Override
  618. public AggregateConfigProvider createAggregateConfig(final String protocol, final String ircd,
  619. final String network, final String server, final String channel) {
  620. final ConfigManager configManager = new ConfigManager(this, protocol, ircd, network, server,
  621. channel);
  622. setUpConfigManager(configManager);
  623. return configManager;
  624. }
  625. }