1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

# coding=utf-8 

# 

# Copyright (C) 2010-2012 Platform Computing 

# 

# This library is free software; you can redistribute it and/or 

# modify it under the terms of the GNU Lesser General Public 

# License as published by the Free Software Foundation; either 

# version 2.1 of the License, or (at your option) any later version. 

# 

# This library is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 

# Lesser General Public License for more details. 

# 

# You should have received a copy of the GNU Lesser General Public 

# License along with this library; if not, write to the Free Software 

# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA 

# 

''' 

Set of functions to parse stuff. 

 

Created on Jun 28, 2011 

 

@author: tmetsch 

''' 

 

# disabling 'Too many local variables' pylint check (text renderings :-() 

# disabling 'Too many branches' pylint check (text renderings :-() 

# pylint: disable=R0914,R0912 

 

from occi.core_model import Category, Link, Mixin, Kind 

 

#============================================================================== 

# Following are text/occi and text/plain related parsing functions. 

#============================================================================== 

 

 

def get_category(category_string, registry, extras, is_mixin=False): 

    ''' 

    Create a Category from a string rendering. 

 

    If found it will return the object from the registry. 

 

    If is_mixin is set to true it will not match with the registry and just 

    return a Mixin. 

 

    category_string -- A string rendering of a category. 

    registry -- To generate a list of registered categories. 

    extras -- The passed on extras argument 

    is_mixin -- Mixin will be created and no matching will be done. 

    ''' 

    categories = registry.get_categories(extras) 

    # find term 

    term = category_string[:category_string.find(';')].strip() 

 

    # find scheme 

    scheme = find_in_string(category_string, 'scheme') 

 

    if is_mixin: 

        location = find_in_string(category_string, 'location') 

        if not location[-1] == '/': 

            raise AttributeError('Illegal location; must end with /') 

        if location[0] != '/' and location.find('http') != 0: 

            raise AttributeError('Illegal location; Either provide full URL' 

                                 ' or just a path starting with /.') 

        mixin = Mixin(scheme, term, location=location) 

        mixin.extras = registry.get_extras(extras) 

 

        try: 

            related = find_in_string(category_string, 'rel') 

        except AttributeError: 

            return mixin 

        else: 

            for item in categories: 

                if str(item) == related: 

                    mixin.related = [item] 

                    return mixin 

            raise AttributeError('Related category cannot be found.') 

 

    # return the category from registry... 

    tmp = Category(scheme, term, '', {}, '') 

    if extras is not None: 

        tmp.extras = registry.get_extras(extras) 

    for item in categories: 

        if item.extras is None: 

            tmp.extras = None 

            if tmp == item: 

                del tmp 

                return item 

            tmp.extras = registry.get_extras(extras) 

        elif item.extras is not None: 

            if tmp == item: 

                del tmp 

                return item 

    raise AttributeError('The following category is not registered within' 

                         + ' this service (See Query interfaces): ' 

                         + str(scheme) + str(term)) 

 

 

def get_category_str(category, registry): 

    ''' 

    Create a string rendering for a Category. 

 

    category -- A category. 

    registry -- registry to retrieve hostname. 

    ''' 

 

    tmp = '' 

    tmp += category.term 

    tmp += '; scheme="' + category.scheme + '"' 

    tmp += '; class="' + repr(category) + '"' 

    if hasattr(category, 'title') and category.title is not '': 

        tmp += '; title="' + category.title + '"' 

    if hasattr(category, 'related') and len(category.related) > 0: 

        rel_list = [] 

        for item in category.related: 

            rel_list.append(str(item)) 

        tmp += '; rel="' + ' '.join(rel_list) + '"' 

    if hasattr(category, 'location') and category.location is not None: 

        tmp += '; location="' 

        if category.location.find('http') == -1: 

            tmp += registry.get_hostname() 

        tmp += category.location + '"' 

    if hasattr(category, 'attributes') and len(category.attributes) > 0: 

        attr_list = [] 

        for item in category.attributes: 

            if category.attributes[item] == 'required': 

                attr_list.append(item + '{required}') 

            elif category.attributes[item] == 'immutable': 

                attr_list.append(item + '{immutable}') 

            else: 

                attr_list.append(item) 

        tmp += '; attributes="' + ' '.join(attr_list) + '"' 

    if hasattr(category, 'actions') and len(category.actions) > 0: 

        action_list = [] 

        for item in category.actions: 

            action_list.append(str(item)) 

        tmp += '; actions="' + ' '.join(action_list) + '"' 

    return tmp 

 

 

def _get_link_categories(categories, registry, extras): 

    ''' 

    Determine the kind ans mixins for inline link creation. 

 

    categories -- String with a set of category string definitions. 

    registry -- Registry used for this call. 

    extras -- Passed on extra object. 

    ''' 

    tmp_kind = None 

    tmp_mixins = [] 

    for tmp_cat in categories.split(' '): 

        tempus = tmp_cat.split('#') 

        link_category = get_category(tempus[1].strip() + ';scheme="' 

                                     + tempus[0].strip() + '#"', registry, 

                                     extras) 

        if isinstance(link_category, Kind): 

            tmp_kind = link_category 

        else: 

            tmp_mixins.append(link_category) 

 

    return tmp_kind, tmp_mixins 

 

 

def get_link(link_string, source, registry, extras): 

    ''' 

    Create a Link from a string rendering. 

 

    Also note that the link_id is set but is not yet registered as resource. 

 

    link_string -- A string rendering of a link. 

    source -- The source entity. 

    registry -- Registry used for this call. 

    extras -- Passed on extra object. 

    ''' 

    tmp = link_string.find('<') + 1 

    target_id = link_string[tmp:link_string.rfind('>', tmp)].strip() 

 

    try: 

        link_id = find_in_string(link_string, 'self') 

    except AttributeError: 

        link_id = None 

 

    try: 

        tmp_category = find_in_string(link_string, 'category') 

    except AttributeError: 

        raise AttributeError('Could not determine the Category of the Link.') 

 

    tmp_kind, tmp_mixins = _get_link_categories(tmp_category, registry, extras) 

 

    if tmp_kind is None: 

        raise AttributeError('Unable to find the Kind of the Link.') 

 

    attributes = {} 

    attr_begin = link_string.find('category="') + 12 + len(tmp_category) 

    attributes_str = link_string[attr_begin:] 

    for attribute in attributes_str.split(';'): 

        tmp = attribute.strip().split('=') 

        if len(tmp) == 2: 

            attributes[tmp[0].strip()] = tmp[1].rstrip('"').lstrip('"').strip() 

 

    try: 

        if not target_id.find(registry.get_hostname()): 

            target_id = target_id.replace(registry.get_hostname(), '') 

        target = registry.get_resource(target_id, extras) 

    except KeyError: 

        # FUTURE_IMPROVEMENT: string links 

        raise AttributeError('The target for the link cannot be found: ' 

                             + target_id) 

 

    link = Link(link_id, tmp_kind, tmp_mixins, source, target) 

    link.attributes = attributes 

    return link 

 

 

def get_link_str(link): 

    ''' 

    Create a string rendering for a Link. 

 

    link -- A link. 

    ''' 

    tmp = '<' + link.target.identifier + '>' 

    tmp += '; rel="' + str(link.target.kind) + '"' 

    tmp += '; self="' + str(link.identifier) + '"' 

    tmp += '; category="' + str(link.kind) 

 

    if len(link.mixins) > 0: 

        for mixin in link.mixins: 

            tmp = tmp + ' ' + str(mixin) 

 

    tmp += '"' 

 

    link.attributes['occi.core.id'] = link.identifier 

    link.attributes['occi.core.source'] = link.source.identifier 

    # FUTURE_IMPROVEMENT: string links 

    link.attributes['occi.core.target'] = link.target.identifier 

 

    if len(link.attributes) > 0: 

        attr_str_list = [] 

        for item in link.attributes: 

            attr_str_list.append(item + '="' + link.attributes[item] + '"') 

        tmp += '; ' + '; '.join(attr_str_list) 

    return tmp 

 

 

def get_attributes(attribute_string): 

    ''' 

    Retrieve the attributes from the HTTP X-OCCI-Attribute rendering. 

    ''' 

    tmp = _strip_all(attribute_string) 

    if tmp.find('=') == -1: 

        raise AttributeError('Mailformed Attribute description!') 

    key = _strip_all(tmp[:tmp.find('=')]) 

    value = tmp[tmp.find('=') + 1:] 

    if value.find('"') is not -1: 

        value = _strip_all(value) 

 

    return key, value 

 

#============================================================================== 

# Helpers 

#============================================================================== 

 

 

def _strip_all(string): 

    ''' 

    Removes beginning / ending quotes and whitespaces. 

    ''' 

    return string.lstrip().lstrip('"').rstrip().rstrip('"') 

 

 

def find_in_string(string, name): 

    ''' 

    Search for string which is surrounded by '<name>=' and ';'. Raises 

    AttributeError if value cannot be found. 

 

    string -- The string to look into. 

    name -- The name of the value to look for. 

    ''' 

    begin = string.find(name + '=') 

    end = string.find(';', begin) 

    result = string[begin + len(name) + 1:end].rstrip('"').lstrip('"').strip() 

    if begin == -1: 

        raise AttributeError('Could not determine the value for: ' + name) 

    return result