SmartAPI
Open Source .NET RQL library for RedDot CMS / OpenText WSM Management Server
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
PageElement.cs
Go to the documentation of this file.
1 ï»¿// SmartAPI - .Net programmatic access to RedDot servers
2 //
3 // Copyright (C) 2013 erminas GbR
4 //
5 // This program is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free Software Foundation,
7 // either version 3 of the License, or (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 // See the GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License along with this program.
14 // If not, see <http://www.gnu.org/licenses/>.
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Globalization;
19 using System.Reflection;
20 using System.Xml;
21 using erminas.SmartAPI.CMS.Project.ContentClasses.Elements;
22 using erminas.SmartAPI.Exceptions;
23 using erminas.SmartAPI.Utils;
24 
25 namespace erminas.SmartAPI.CMS.Project.Pages.Elements
26 {
27  public interface IPageElementFactory
28  {
29  IPageElement CreateElement(IProject project, Guid elementGuid, ILanguageVariant languageVariant);
30  }
31 
33  {
34  static PageElementFactory()
35  {
36  Instance = new PageElementFactory();
37  }
38 
39  private PageElementFactory()
40  {
41  }
42 
43  public IPageElement CreateElement(IProject project, Guid elementGuid, ILanguageVariant languageVariant)
44  {
45  return PageElement.CreateElement(project, elementGuid, languageVariant);
46  }
47 
48  public static IPageElementFactory Instance { get; set; }
49  }
50 
60  internal abstract class PageElement : PartialRedDotProjectObject, IPageElement
61  {
62  private const string RETRIEVE_PAGE_ELEMENT = @"<ELT action=""load"" guid=""{0}""/>";
63 
64  private static readonly Dictionary<ElementType, Type> TYPES = new Dictionary<ElementType, Type>();
65 
66  protected ElementType Type;
67  private ILanguageVariant _languageVariant;
68  private IPage _page;
69 
70  static PageElement()
71  {
72  foreach (Type curType in typeof (PageElement).Assembly.GetTypes())
73  {
74  foreach (object curAttr in curType.GetCustomAttributes(typeof (PageElementType), false))
75  {
76  if (
77  curType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null,
78  new[] {typeof (Project), typeof (XmlElement)}, null) == null)
79  {
80  throw new SmartAPIInternalException(
81  string.Format("{0} does not contain a constructor (Project, XmlElement)", curType.Name));
82  }
83  var type = ((PageElementType) curAttr).Type;
84  if (TYPES.ContainsKey(type))
85  {
86  throw new SmartAPIInternalException(string.Format("Multiple definititions of {0}: {1} and {2}",
87  type, TYPES[type].Name, curType.Name));
88  }
89  TYPES.Add(type, curType);
90  }
91  }
92  }
93 
94  protected PageElement(IProject project, Guid guid, ILanguageVariant languageVariant) : base(project, guid)
95  {
96  LanguageVariant = languageVariant;
97  }
98 
99  protected PageElement(IProject project, XmlElement xmlElement) : base(project, xmlElement)
100  {
101  LoadXml();
102  }
103 
110  public static IPageElement CreateElement(IProject project, XmlElement xmlElement)
111  {
112  var typeValue = (ElementType) int.Parse(xmlElement.GetAttributeValue("elttype"));
113  Type type;
114  if (!TYPES.TryGetValue(typeValue, out type))
115  {
116  throw new ArgumentException(string.Format("Unknown element type: {0}", typeValue));
117  }
118  return
119  (IPageElement)
120  Activator.CreateInstance(type, BindingFlags.NonPublic | BindingFlags.Instance, null,
121  new object[] {project, xmlElement}, CultureInfo.InvariantCulture);
122  }
123 
131  public static IPageElement CreateElement(IProject project, Guid elementGuid, ILanguageVariant languageVariant)
132  {
133  using (new LanguageContext(languageVariant))
134  {
135  XmlDocument xmlDoc = project.ExecuteRQL(string.Format(RETRIEVE_PAGE_ELEMENT, elementGuid.ToRQLString()));
136  var xmlNode = (XmlElement) xmlDoc.GetElementsByTagName("ELT")[0];
137  return CreateElement(project, xmlNode);
138  }
139  }
140 
141  public virtual ElementType ElementType
142  {
143  get
144  {
145  if (Type == ElementType.None)
146  {
147  object[] types = GetType().GetCustomAttributes(typeof (PageElementType), false);
148  if (types.Length != 1)
149  {
150  throw new SmartAPIInternalException(string.Format("Undefined ElementType for {0}",
151  GetType().Name));
152  }
153  Type = ((PageElementType) types[0]).Type;
154  }
155  return Type;
156  }
157  set { Type = value; }
158  }
159 
160  public ILanguageVariant LanguageVariant
161  {
162  get { return _languageVariant; }
163  private set { _languageVariant = value; }
164  }
165 
166  public IPage Page
167  {
168  get { return LazyLoad(ref _page); }
169  }
170 
171  public static void RegisterType(ElementType typeValue, Type type)
172  {
173  if (!typeof (PageElement).IsAssignableFrom(type))
174  {
175  //use format to be safe from potentially refactoring names
176  throw new ArgumentException(String.Format("TypeId is not a subclass of {0}", typeof (PageElement).Name));
177  }
178 
179  if (TYPES.ContainsKey(typeValue))
180  {
181  throw new ArgumentException("There is already a type registered for " + typeValue);
182  }
183 
184  TYPES.Add(typeValue, type);
185  }
186 
187  protected override sealed void LoadWholeObject()
188  {
189  LoadXml();
190  LoadWholePageElement();
191  }
192 
193  protected abstract void LoadWholePageElement();
194 
195  protected override XmlElement RetrieveWholeObject()
196  {
197  using (new LanguageContext(LanguageVariant))
198  {
199  return
200  (XmlElement)
201  Project.ExecuteRQL(string.Format(RETRIEVE_PAGE_ELEMENT, Guid.ToRQLString()))
202  .GetElementsByTagName("ELT")[0];
203  }
204  }
205 
206  private void LoadXml()
207  {
208  //language variant must be loaded before the page referenced by pageguid, because it is used in its c'tor
209  EnsuredInit(ref _languageVariant, "languagevariantid", Project.LanguageVariants.Get);
210  EnsuredInit(ref _page, "pageguid", x => new Page(Project, GuidConvert(x), LanguageVariant));
211  }
212  }
213 }