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 26KB

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