PageRenderTime 32ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/CompositeC1/Composite/C1Console/Trees/TreeFacadeImpl.cs

#
C# | 676 lines | 477 code | 157 blank | 42 comment | 38 complexity | 9eef411ef140a4f91768c8f5fda2c4ac MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * The contents of this web application are subject to the Mozilla Public License Version
  3. * 1.1 (the "License"); you may not use this web application except in compliance with
  4. * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/.
  5. *
  6. * Software distributed under the License is distributed on an "AS IS" basis,
  7. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. * for the specific language governing rights and limitations under the License.
  9. *
  10. * The Original Code is owned by and the Initial Developer of the Original Code is
  11. * Composite A/S (Danish business reg.no. 21744409). All Rights Reserved
  12. *
  13. * Section 11 of the License is EXPRESSLY amended to include a provision stating
  14. * that any dispute, including but not limited to disputes related to the enforcement
  15. * of the License, to which Composite A/S as owner of the Original Code, as Initial
  16. * Developer or in any other role, becomes a part to shall be governed by Danish law
  17. * and be initiated before the Copenhagen City Court ("K�benhavns Byret")
  18. */
  19. using System;
  20. using System.Collections.Generic;
  21. using System.IO;
  22. using System.Linq;
  23. using System.Reflection;
  24. using System.Text;
  25. using System.Threading;
  26. using System.Web.Hosting;
  27. using System.Xml;
  28. using System.Xml.Linq;
  29. using System.Xml.Xsl;
  30. using Composite.C1Console.Elements;
  31. using Composite.C1Console.Elements.Plugins.ElementAttachingProvider;
  32. using Composite.C1Console.Events;
  33. using Composite.C1Console.Security;
  34. using Composite.C1Console.Trees.Foundation;
  35. using Composite.C1Console.Trees.Foundation.AttachmentPoints;
  36. using Composite.C1Console.Users;
  37. using Composite.Core;
  38. using Composite.Core.Collections.Generic;
  39. using Composite.Core.Configuration;
  40. using Composite.Core.Extensions;
  41. using Composite.Core.IO;
  42. using Composite.Core.Linq;
  43. using Composite.Core.ResourceSystem;
  44. using Composite.Core.Threading;
  45. using Composite.Core.Types;
  46. using Composite.Core.Xml;
  47. using Composite.Data;
  48. using Composite.Data.GeneratedTypes;
  49. using Composite.Data.ProcessControlled;
  50. using Composite.Data.Transactions;
  51. using Composite.Data.Types;
  52. using Composite.Plugins.Elements.ElementProviders.DeveloperApplicationProvider;
  53. namespace Composite.C1Console.Trees
  54. {
  55. [FlushAttribute("ReloadAllTrees")]
  56. internal sealed class TreeFacadeImpl : ITreeFacade
  57. {
  58. private static readonly string LogTitle = "TreeFacade";
  59. private const string XslFilename = "Tree.xsl";
  60. private static readonly ResourceLocker<Resources> _resourceLocker = new ResourceLocker<Resources>(new Resources(), Resources.Initialize, false);
  61. private static readonly object _reloadAttachmentPointsSyncRoot = new object();
  62. public void Initialize()
  63. {
  64. using (_resourceLocker.Locker)
  65. {
  66. if (!GlobalInitializerFacade.IsReinitializingTheSystem)
  67. {
  68. DataEventSystemFacade.SubscribeToDataAfterAdd<IDataItemTreeAttachmentPoint>(OnUpdateTreeAttachmentPoints, true);
  69. DataEventSystemFacade.SubscribeToDataDeleted<IDataItemTreeAttachmentPoint>(OnUpdateTreeAttachmentPoints, true);
  70. DataEventSystemFacade.SubscribeToStoreChanged<IDataItemTreeAttachmentPoint>(OnTreeAttachmentPointsStoreChange, true);
  71. GeneratedTypesFacade.SubscribeToUpdateTypeEvent(OnDataTypeChanged);
  72. var treeAuxiliaryAncestorProvider = new C1Console.Trees.TreeAuxiliaryAncestorProvider();
  73. AuxiliarySecurityAncestorFacade.AddAuxiliaryAncestorProvider<TreeSimpleElementEntityToken>(treeAuxiliaryAncestorProvider, true);
  74. AuxiliarySecurityAncestorFacade.AddAuxiliaryAncestorProvider<TreeFunctionElementGeneratorEntityToken>(treeAuxiliaryAncestorProvider, true);
  75. AuxiliarySecurityAncestorFacade.AddAuxiliaryAncestorProvider<TreeDataFieldGroupingElementEntityToken>(treeAuxiliaryAncestorProvider, true);
  76. AuxiliarySecurityAncestorFacade.AddAuxiliaryAncestorProvider<DataEntityToken>(treeAuxiliaryAncestorProvider, true);
  77. AuxiliarySecurityAncestorFacade.AddAuxiliaryAncestorProvider<TreePerspectiveEntityToken>(treeAuxiliaryAncestorProvider, true);
  78. _resourceLocker.Resources.PersistentAttachmentPoints = new Dictionary<string, List<IAttachmentPoint>>();
  79. LoadAllTrees();
  80. InitializeTreeAttachmentPoints();
  81. TreeSharedRootsFacade.Clear();
  82. var fileWatcher = new C1FileSystemWatcher(TreeDefinitionsFolder, "*.xml");
  83. fileWatcher.Created += OnReloadTrees;
  84. fileWatcher.Deleted += OnReloadTrees;
  85. fileWatcher.Changed += OnReloadTrees;
  86. fileWatcher.Renamed += OnReloadTrees;
  87. fileWatcher.EnableRaisingEvents = true;
  88. _resourceLocker.Resources.FileSystemWatcher = fileWatcher;
  89. _resourceLocker.Resources.RootEntityToken = ElementFacade.GetRootsWithNoSecurity().First().ElementHandle.EntityToken;
  90. }
  91. }
  92. }
  93. public Tree GetTree(string treeId)
  94. {
  95. Tree tree;
  96. using (_resourceLocker.ReadLocker)
  97. {
  98. _resourceLocker.Resources.Trees.TryGetValue(treeId, out tree);
  99. }
  100. return tree;
  101. }
  102. public IEnumerable<Tree> AllTrees
  103. {
  104. get
  105. {
  106. using (_resourceLocker.ReadLocker)
  107. {
  108. return _resourceLocker.Resources.Trees.Values.Evaluate();
  109. }
  110. }
  111. }
  112. public bool HasAttachmentPoints(EntityToken parentEntityToken)
  113. {
  114. using (_resourceLocker.ReadLocker)
  115. {
  116. return _resourceLocker.Resources.Trees.Any(f => f.Value.HasAttachmentPoints(parentEntityToken));
  117. }
  118. }
  119. public bool HasPossibleAttachmentPoints(EntityToken parentEntityToken)
  120. {
  121. using (_resourceLocker.ReadLocker)
  122. {
  123. return _resourceLocker.Resources.Trees.Any(f => f.Value.HasPossibleAttachmentPoints(parentEntityToken));
  124. }
  125. }
  126. public IEnumerable<Tree> GetTreesByEntityToken(EntityToken parentEntityToken)
  127. {
  128. using (_resourceLocker.ReadLocker)
  129. {
  130. return _resourceLocker.Resources.Trees.Values.Where(tree => tree.HasAttachmentPoints(parentEntityToken));
  131. }
  132. }
  133. public IEnumerable<Element> GetElementsByTreeId(string treeId, EntityToken parentEntityToken, Dictionary<string, string> piggybag)
  134. {
  135. Tree tree = GetTree(treeId);
  136. if (tree == null) return new Element[] { };
  137. var dynamicContext = new TreeNodeDynamicContext(TreeNodeDynamicContextDirection.Down)
  138. {
  139. Piggybag = piggybag,
  140. CurrentEntityToken = parentEntityToken,
  141. CurrentTreeNode = tree.RootTreeNode
  142. };
  143. return tree.RootTreeNode.GetElements(parentEntityToken, dynamicContext);
  144. }
  145. public Tree LoadTreeFromDom(string treeId, XDocument document)
  146. {
  147. string xslFilename = Path.Combine(TreeDefinitionsFolder, XslFilename);
  148. var fileInfo = new C1FileInfo(xslFilename);
  149. // The default xslt transformation does no changes and it's xsl file has size of 358 bytes, skipping this file saves up to 0.5 second on site startup
  150. if (fileInfo.Exists && fileInfo.Length != 358)
  151. {
  152. try
  153. {
  154. var newDocument = new XDocument();
  155. using (XmlWriter xmlWriter = newDocument.CreateWriter())
  156. {
  157. var xslTransform = new XslCompiledTransform();
  158. xslTransform.LoadFromPath(xslFilename);
  159. xslTransform.Transform(document.CreateReader(), xmlWriter);
  160. }
  161. document = newDocument;
  162. }
  163. catch (Exception ex)
  164. {
  165. Log.LogCritical("TreeFacade", "Failed to apply xslt on the tree {0} with the following exception", treeId);
  166. Log.LogCritical("TreeFacade", ex);
  167. }
  168. }
  169. return Load(treeId, document);
  170. }
  171. public void OnFlush()
  172. {
  173. using (_resourceLocker.Locker)
  174. {
  175. _resourceLocker.Resources.PersistentAttachmentPoints = new Dictionary<string, List<IAttachmentPoint>>();
  176. Initialize();
  177. }
  178. }
  179. private void OnDataTypeChanged(EventArgs eventArgs)
  180. {
  181. OnReloadTrees(null, null);
  182. }
  183. private void OnReloadTrees(object sender, FileSystemEventArgs e)
  184. {
  185. if (HostingEnvironment.ApplicationHost.ShutdownInitiated())
  186. {
  187. return;
  188. }
  189. Thread.CurrentThread.CurrentCulture = UserSettings.CultureInfo;
  190. using (GlobalInitializerFacade.CoreIsInitializedScope)
  191. using (_resourceLocker.Locker)
  192. {
  193. TimeSpan timeSpan = DateTime.Now - _resourceLocker.Resources.LastFileChange;
  194. if (timeSpan.TotalMilliseconds > 100)
  195. {
  196. _resourceLocker.Resources.LastFileChange = DateTime.Now;
  197. ReloadAllTrees();
  198. }
  199. }
  200. }
  201. private void LoadAllTrees()
  202. {
  203. using (_resourceLocker.Locker)
  204. {
  205. _resourceLocker.Resources.Trees = new Dictionary<string, Tree>();
  206. Log.LogVerbose(LogTitle, "Loading all tree definitions from {0}", TreeDefinitionsFolder);
  207. foreach (string filename in C1Directory.GetFiles(TreeDefinitionsFolder, "*.xml"))
  208. {
  209. string treeId = Path.GetFileName(filename);
  210. try
  211. {
  212. Log.LogVerbose(LogTitle, "Loading tree from file: " + filename);
  213. int t1 = Environment.TickCount;
  214. Tree tree = LoadTreeFromFile(treeId);
  215. if (tree.BuildResult.ValidationErrors.Any())
  216. {
  217. Log.LogError(LogTitle, "Tree {0} was not loaded due to the following validation errors", treeId);
  218. var sb = new StringBuilder();
  219. foreach (ValidationError validationError in tree.BuildResult.ValidationErrors)
  220. {
  221. sb.AppendLine(string.Format("{0} at {1}", validationError.Message, validationError.XPath));
  222. Log.LogError("TreeFacade", string.Format("{0} at {1} in {2}", validationError.Message, validationError.XPath, filename));
  223. }
  224. //Tree errorTree = CreateErrorTree(treeId, sb.ToString());
  225. //if (_resourceLocker.Resources.Trees.ContainsKey(errorTree.TreeId) == false)
  226. //{
  227. // _resourceLocker.Resources.Trees.Add(errorTree.TreeId, errorTree);
  228. //}
  229. }
  230. else
  231. {
  232. _resourceLocker.Resources.Trees.Add(treeId, tree);
  233. }
  234. int msElapsed = Environment.TickCount - t1;
  235. if (msElapsed > 20)
  236. {
  237. Log.LogVerbose("TreeFacade", "Time spend on loading the tree: " + msElapsed + "ms, file: " + filename);
  238. }
  239. }
  240. catch (Exception ex)
  241. {
  242. Log.LogError("TreeFacade: Failed to load the tree " + treeId, ex);
  243. //Tree errorTree = CreateErrorTree(treeId, ex.Message);
  244. //if (_resourceLocker.Resources.Trees.ContainsKey(errorTree.TreeId) == false)
  245. //{
  246. // _resourceLocker.Resources.Trees.Add(errorTree.TreeId, errorTree);
  247. //}
  248. }
  249. }
  250. }
  251. }
  252. private Tree CreateErrorTree(string treeId, string errorMessage)
  253. {
  254. var tree = new Tree("ERRORTREE:" + treeId)
  255. {
  256. BuildProcessContext = new BuildProcessContext(),
  257. BuildResult = new BuildResult()
  258. };
  259. tree.AttachmentPoints.Add(
  260. new EntityTokenAttachmentPoint
  261. {
  262. EntityToken = new DeveloperApplicationProviderEntityToken(DeveloperApplicationProviderEntityToken.TreeDefinitionId, treeId),
  263. Position = ElementAttachingProviderPosition.Top
  264. }
  265. );
  266. tree.RootTreeNode = new RootTreeNode()
  267. {
  268. Id = "ERRORTREEROOT",
  269. Tree = tree
  270. };
  271. var simpleElementTreeNode = new SimpleElementTreeNode()
  272. {
  273. Label = StringResourceSystemFacade.GetString("Composite.C1Console.Trees", "KeyFacade.ErrorTreeNode.Label"),
  274. Id = "ERROR",
  275. ToolTip = errorMessage,
  276. Icon = ResourceHandle.BuildIconFromDefaultProvider("close"),
  277. Tree = tree
  278. };
  279. var messageBoxActionNode = new MessageBoxActionNode
  280. {
  281. Id = 1,
  282. OwnerNode = simpleElementTreeNode,
  283. Label = StringResourceSystemFacade.GetString("Composite.C1Console.Trees", "KeyFacade.ErrorTreeNode.ShowMessage.Label"),
  284. ToolTip = StringResourceSystemFacade.GetString("Composite.C1Console.Trees", "KeyFacade.ErrorTreeNode.ShowMessage.ToolTip"),
  285. Icon = ResourceHandle.BuildIconFromDefaultProvider("log-showlog"),
  286. Title = StringResourceSystemFacade.GetString("Composite.C1Console.Trees", "KeyFacade.ErrorTreeNode.ShowMessage.Title"),
  287. Message = errorMessage,
  288. DialogType = DialogType.Error,
  289. PermissionTypes = new List<PermissionType> { PermissionType.Administrate }
  290. };
  291. simpleElementTreeNode.AddActionNode(messageBoxActionNode);
  292. tree.RootTreeNode.AddChildTreeNode(simpleElementTreeNode);
  293. return tree;
  294. }
  295. private Tree LoadTreeFromFile(string treeId)
  296. {
  297. string filename = Path.Combine(TreeDefinitionsFolder, treeId);
  298. for (int i = 0; i < 10; i++)
  299. {
  300. try
  301. {
  302. XDocument document = XDocumentUtils.Load(filename);
  303. return LoadTreeFromDom(treeId, document);
  304. }
  305. catch (IOException)
  306. {
  307. Thread.Sleep(100);
  308. }
  309. }
  310. throw new InvalidOperationException("Could not load tree " + treeId);
  311. }
  312. private void ReloadAllTrees()
  313. {
  314. using (ThreadDataManager.EnsureInitialize())
  315. {
  316. LoadAllTrees();
  317. InitializeTreeAttachmentPoints();
  318. TreeSharedRootsFacade.Clear();
  319. using (_resourceLocker.ReadLocker)
  320. {
  321. var refreshTreeMessageQueueItem = new RefreshTreeMessageQueueItem
  322. {
  323. EntityToken = _resourceLocker.Resources.RootEntityToken
  324. };
  325. ConsoleMessageQueueFacade.Enqueue(refreshTreeMessageQueueItem, null);
  326. }
  327. }
  328. }
  329. private Tree Load(string treeId, XDocument document)
  330. {
  331. Tree tree = TreeBuilder.BuildTree(treeId, document);
  332. //if (tree.BuildResult.ValidationErrors.Count() == 0)
  333. //{
  334. // tree.LogTree();
  335. //}
  336. return tree;
  337. }
  338. private void OnTreeAttachmentPointsStoreChange(object sender, StoreEventArgs storeEventArgs)
  339. {
  340. if (!storeEventArgs.DataEventsFired)
  341. {
  342. InitializeTreeAttachmentPoints();
  343. }
  344. }
  345. private void OnUpdateTreeAttachmentPoints(object sender, DataEventArgs dataEventArgs)
  346. {
  347. InitializeTreeAttachmentPoints();
  348. }
  349. #region Attachment points
  350. public bool AddPersistedAttachmentPoint(string treeId, Type interfaceType, object keyValue, ElementAttachingProviderPosition position = ElementAttachingProviderPosition.Top)
  351. {
  352. var attachmentPoint = DataFacade.BuildNew<IDataItemTreeAttachmentPoint>();
  353. attachmentPoint.Id = Guid.NewGuid();
  354. attachmentPoint.TreeId = treeId;
  355. attachmentPoint.Position = position.ToString();
  356. attachmentPoint.InterfaceType = TypeManager.SerializeType(interfaceType);
  357. attachmentPoint.KeyValue = ValueTypeConverter.Convert<string>(keyValue);
  358. bool added = false;
  359. using (var transactionScope = TransactionsFacade.CreateNewScope())
  360. {
  361. bool exist =
  362. (from d in DataFacade.GetData<IDataItemTreeAttachmentPoint>()
  363. where d.InterfaceType == attachmentPoint.InterfaceType && d.KeyValue == attachmentPoint.KeyValue && d.TreeId == treeId
  364. select d).Any();
  365. if (!exist)
  366. {
  367. DataFacade.AddNew<IDataItemTreeAttachmentPoint>(attachmentPoint);
  368. added = true;
  369. }
  370. transactionScope.Complete();
  371. }
  372. return added;
  373. }
  374. public bool RemovePersistedAttachmentPoint(string treeId, Type interfaceType, object keyValue)
  375. {
  376. string serializedInterfaceType = TypeManager.SerializeType(interfaceType);
  377. string serializedKeyValue = ValueTypeConverter.Convert<string>(keyValue);
  378. bool removed = false;
  379. using (var transactionScope = TransactionsFacade.CreateNewScope())
  380. {
  381. IEnumerable<IDataItemTreeAttachmentPoint> dataItemTreeAttachmentPoints =
  382. (from d in DataFacade.GetData<IDataItemTreeAttachmentPoint>()
  383. where d.InterfaceType == serializedInterfaceType && d.KeyValue == serializedKeyValue && d.TreeId == treeId
  384. select d).Evaluate();
  385. if (dataItemTreeAttachmentPoints.Any())
  386. {
  387. DataFacade.Delete<IDataItemTreeAttachmentPoint>(dataItemTreeAttachmentPoints);
  388. removed = true;
  389. }
  390. transactionScope.Complete();
  391. }
  392. return removed;
  393. }
  394. /// <summary>
  395. /// This will add a attachment point until the system flushes.
  396. /// This can be used by element provider implementors to attach trees to their exising trees.
  397. /// </summary>
  398. /// <param name="treeId"></param>
  399. /// <param name="entityToken"></param>
  400. /// <param name="position"></param>
  401. public bool AddCustomAttachmentPoint(string treeId, EntityToken entityToken, ElementAttachingProviderPosition position = ElementAttachingProviderPosition.Top)
  402. {
  403. Tree tree = GetTree(treeId);
  404. if (tree == null) return false;
  405. var customAttachmentPoint = new CustomAttachmentPoint(entityToken, position);
  406. tree.AttachmentPoints.Add(customAttachmentPoint);
  407. List<IAttachmentPoint> attachmentPoints;
  408. using (_resourceLocker.Locker)
  409. {
  410. if (_resourceLocker.Resources.PersistentAttachmentPoints.TryGetValue(treeId, out attachmentPoints) == false)
  411. {
  412. attachmentPoints = new List<IAttachmentPoint>();
  413. _resourceLocker.Resources.PersistentAttachmentPoints.Add(treeId, attachmentPoints);
  414. }
  415. }
  416. attachmentPoints.Add(customAttachmentPoint);
  417. return true;
  418. }
  419. private void ClearAttachmentPoints<T>()
  420. where T : IAttachmentPoint
  421. {
  422. using (_resourceLocker.ReadLocker)
  423. {
  424. foreach (Tree tree in _resourceLocker.Resources.Trees.Values)
  425. {
  426. tree.ClearAttachmentPoints<T>();
  427. }
  428. }
  429. }
  430. private void InitializeTreeAttachmentPoints()
  431. {
  432. lock (_reloadAttachmentPointsSyncRoot)
  433. {
  434. ClearAttachmentPoints<DynamicDataItemAttachmentPoint>();
  435. IEnumerable<IDataItemTreeAttachmentPoint> attachmentPoints = DataFacade.GetData<IDataItemTreeAttachmentPoint>().Evaluate();
  436. foreach (IDataItemTreeAttachmentPoint attachmentPoint in attachmentPoints)
  437. {
  438. Tree tree = GetTree(attachmentPoint.TreeId);
  439. if (tree == null)
  440. {
  441. string treePath = Path.Combine(TreeDefinitionsFolder, attachmentPoint.TreeId);
  442. if (!C1File.Exists(treePath)) // This ensures that invalid, but existing trees does not remove these attachment points
  443. {
  444. if (DataFacade.WillDeleteSucceed(attachmentPoint))
  445. {
  446. Log.LogWarning("TreeFacade", "A data item attachment points is referring a non existing tree '{0}' and is deleted", attachmentPoint.TreeId);
  447. // Preventing events so this method won't call itself recursively
  448. DataFacade.Delete(attachmentPoint, true, CascadeDeleteType.Allow);
  449. }
  450. }
  451. continue;
  452. }
  453. Type interfaceType = TypeManager.GetType(attachmentPoint.InterfaceType);
  454. object keyValue = ValueTypeConverter.Convert(attachmentPoint.KeyValue, interfaceType.GetKeyProperties()[0].PropertyType);
  455. var position = (ElementAttachingProviderPosition)Enum.Parse(typeof(ElementAttachingProviderPosition), attachmentPoint.Position);
  456. var dataItemTreeAttachmentPoint = new DynamicDataItemAttachmentPoint
  457. {
  458. InterfaceType = interfaceType,
  459. KeyValue = keyValue,
  460. Position = position
  461. };
  462. // Log.LogVerbose("TreeFacade", string.Format("Tree with id '{0}' is dynamically attached to the data type '{1}' with key value of '{2}'", attachmentPoint.TreeId, interfaceType, keyValue));
  463. tree.AttachmentPoints.Add(dataItemTreeAttachmentPoint);
  464. DataEventSystemFacade.SubscribeToDataDeleted(interfaceType, OnDataItemDeleted, false);
  465. }
  466. using (_resourceLocker.ReadLocker)
  467. {
  468. foreach (var kvp in _resourceLocker.Resources.PersistentAttachmentPoints)
  469. {
  470. Tree tree = GetTree(kvp.Key);
  471. if (tree == null) continue;
  472. tree.AttachmentPoints.AddRange(kvp.Value);
  473. }
  474. }
  475. }
  476. }
  477. private static void OnDataItemDeleted(object sender, DataEventArgs dataEventArgs)
  478. {
  479. Type interfaceType = dataEventArgs.Data.DataSourceId.InterfaceType;
  480. if (typeof(IPublishControlled).IsAssignableFrom(interfaceType) &&
  481. !dataEventArgs.Data.DataSourceId.DataScopeIdentifier.Equals(DataScopeIdentifier.Administrated))
  482. {
  483. return; // Only remove attachment point if its the admin version of a publishable data item that have been delete
  484. }
  485. if (typeof(ILocalizedControlled).IsAssignableFrom(interfaceType) &&
  486. DataFacade.ExistsInAnyLocale(interfaceType, dataEventArgs.Data.DataSourceId.LocaleScope))
  487. {
  488. return; // Data exists in other locales, so do not remove this attachment point
  489. }
  490. PropertyInfo propertyInfo = interfaceType.GetKeyProperties()[0];
  491. string keyValue = ValueTypeConverter.Convert<string>(propertyInfo.GetValue(dataEventArgs.Data, null));
  492. IEnumerable<IDataItemTreeAttachmentPoint> attachmentPoints =
  493. from d in DataFacade.GetData<IDataItemTreeAttachmentPoint>()
  494. where
  495. d.InterfaceType == TypeManager.SerializeType(interfaceType) &&
  496. d.KeyValue == keyValue
  497. select d;
  498. DataFacade.Delete<IDataItemTreeAttachmentPoint>(attachmentPoints);
  499. }
  500. private static string TreeDefinitionsFolder
  501. {
  502. get { return PathUtil.Resolve(GlobalSettingsFacade.TreeDefinitionsDirectory); }
  503. }
  504. #endregion
  505. private sealed class Resources
  506. {
  507. public Dictionary<string, Tree> Trees { get; set; }
  508. public Dictionary<string, List<IAttachmentPoint>> PersistentAttachmentPoints { get; set; }
  509. public C1FileSystemWatcher FileSystemWatcher { get; set; }
  510. public DateTime LastFileChange { get; set; }
  511. public EntityToken RootEntityToken { get; set; }
  512. public static void Initialize(Resources resources)
  513. {
  514. resources.Trees = new Dictionary<string, Tree>();
  515. resources.PersistentAttachmentPoints = new Dictionary<string, List<IAttachmentPoint>>();
  516. }
  517. }
  518. }
  519. }