SmartAPI
Open Source .NET RQL library for RedDot CMS / OpenText WSM Management Server
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
RedDotAttribute.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.Globalization;
18 using System.Linq;
19 using erminas.SmartAPI.CMS.Project;
20 using erminas.SmartAPI.Exceptions;
21 
22 namespace erminas.SmartAPI.CMS
23 {
24  [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
25  internal class RedDotAttribute : Attribute
26  {
27  public readonly string ElementName;
28  private IAttributeConvertBase _converterInstance;
29  private Type _converterType;
30  private string _description;
31  private bool _isReadOnly;
32  private Type _targetType;
33 
34  public RedDotAttribute(string elementName)
35  {
36  ElementName = elementName;
37  }
38 
39  public Type ConverterType
40  {
41  get { return _converterType; }
42  set
43  {
44  if (!IsConverterType(value))
45  {
46  throw new SmartAPIInternalException(string.Format("Invalid converter type '{0}' for element {1}",
47  value.Name, ElementName));
48  }
49  try
50  {
51  var interfaceType =
52  value.GetInterfaces()
53  .First(
54  type =>
55  type.IsGenericType && type.GetGenericTypeDefinition() == typeof (IAttributeConverter<>));
56  _targetType = interfaceType.GetGenericArguments()[0];
57  _converterInstance = (IAttributeConvertBase) value.GetConstructor(new Type[0]).Invoke(new object[0]);
58  _converterType = value;
59  } catch (Exception e)
60  {
61  throw new SmartAPIInternalException(
62  string.Format("Invalid converter type '{0}' for element {1}", value.Name, ElementName), e);
63  }
64  }
65  }
66 
67  public string DependsOn { get; set; }
68 
69  public string Description
70  {
71  get { return _description ?? RedDotAttributeDescription.GetDescriptionForElement(ElementName); }
72  set { _description = value; }
73  }
74 
75  public bool IsReadOnly
76  {
77  get { return _converterInstance != null ? _converterInstance.IsReadOnly || _isReadOnly : _isReadOnly; }
78  set { _isReadOnly = value; }
79  }
80 
81  public T ReadFrom<T>(IProjectObject sourceProject, IXmlReadWriteWrapper element)
82  {
83  Type type = typeof (T);
84  return _converterInstance != null
85  ? GetCustomConversion<T>(sourceProject, element, type)
86  : GetDefaultConversion<T>(element, type);
87  }
88 
89  public void WriteTo<T>(IProjectObject targetProject, IXmlReadWriteWrapper element, T value)
90  {
91  if (IsReadOnly)
92  {
93  throw new SmartAPIException((string) null,
94  string.Format("Cannot write to read only attribute {0}", Description));
95  }
96  if (_converterInstance != null)
97  {
98  SetWithCustomConversion(targetProject, element, value);
99  }
100  else
101  {
102  SetWithDefaultConversion(element, value);
103  }
104  }
105 
106  private T GetCustomConversion<T>(IProjectObject sourceProject, IXmlReadWriteWrapper element, Type type)
107  {
108  if (_targetType != type)
109  {
110  throw new SmartAPIInternalException(
111  string.Format("Converter type does not match Convert<T> call for element {0}", ElementName));
112  }
113 
114  return ((IAttributeConverter<T>) _converterInstance).ConvertFrom(sourceProject, element.MergedElement, this);
115  }
116 
117  private T GetDefaultConversion<T>(IXmlReadWriteWrapper element, Type type)
118  {
119  if (type == typeof (string))
120  {
121  return (T) (object) element.GetAttributeValue(ElementName);
122  }
123  if (type == typeof (bool))
124  {
125  return (T) (object) element.GetBoolAttributeValue(ElementName);
126  }
127  if (type == typeof (int?))
128  {
129  return (T) (object) element.GetIntAttributeValue(ElementName);
130  }
131  throw new SmartAPIInternalException(string.Format("No matching conversion for element {0} to type {1}",
132  ElementName, type.Name));
133  }
134 
135  private static bool IsConverterType(Type value)
136  {
137  return
138  value.GetInterfaces()
139  .Any(
140  type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof (IAttributeConverter<>));
141  }
142 
143  private void SetWithCustomConversion<T>(IProjectObject targetProject, IXmlReadWriteWrapper element, T value)
144  {
145  if (typeof (T) != _targetType)
146  {
147  throw new SmartAPIInternalException(
148  string.Format("Converter type {0} does not match Set<T> call for element {1} with type {2}",
149  _targetType.Name, ElementName, typeof (T).Name));
150  }
151 
152  ((IAttributeConverter<T>) _converterInstance).WriteTo(targetProject, element, this, value);
153  }
154 
155  private void SetWithDefaultConversion<T>(IXmlReadWriteWrapper element, T value)
156  {
157  Type type = typeof (T);
158  if (type == typeof (string))
159  {
160  element.SetAttributeValue(ElementName, (string) (object) value);
161  return;
162  }
163 
164  if (type == typeof (bool))
165  {
166  element.SetAttributeValue(ElementName, (bool) (object) value ? "1" : "0");
167  return;
168  }
169  if (type == typeof (int?))
170  {
171  var i = ((int?) (object) value);
172  element.SetAttributeValue(ElementName, i != null ? i.Value.ToString(CultureInfo.InvariantCulture) : null);
173  return;
174  }
175  throw new SmartAPIInternalException(string.Format("No matching conversion for element {0} to type {1}",
176  ElementName, type.Name));
177  }
178  }
179 }