Revision f047f90f

b/Makefile.am
347 347
	htools/Ganeti/HTools/Group.hs \
348 348
	htools/Ganeti/HTools/IAlloc.hs \
349 349
	htools/Ganeti/HTools/Instance.hs \
350
	htools/Ganeti/HTools/JSON.hs \
350 351
	htools/Ganeti/HTools/Loader.hs \
351 352
	htools/Ganeti/HTools/Luxi.hs \
352 353
	htools/Ganeti/HTools/Node.hs \
b/htools/Ganeti/HTools/JSON.hs
1
{-| JSON utility functions. -}
2

  
3
{-
4

  
5
Copyright (C) 2009, 2010, 2011 Google Inc.
6

  
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
11

  
12
This program is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16

  
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301, USA.
21

  
22
-}
23

  
24
module Ganeti.HTools.JSON
25
    ( fromJResult
26
    , readEitherString
27
    , JSRecord
28
    , loadJSArray
29
    , fromObj
30
    , maybeFromObj
31
    , fromObjWithDefault
32
    , fromJVal
33
    , asJSObject
34
    , asObjectList
35
    )
36
    where
37

  
38
import Control.Monad (liftM)
39
import Data.Maybe (fromMaybe)
40
import Text.Printf (printf)
41

  
42
import qualified Text.JSON as J
43

  
44
-- * JSON-related functions
45

  
46
-- | A type alias for the list-based representation of J.JSObject.
47
type JSRecord = [(String, J.JSValue)]
48

  
49
-- | Converts a JSON Result into a monadic value.
50
fromJResult :: Monad m => String -> J.Result a -> m a
51
fromJResult s (J.Error x) = fail (s ++ ": " ++ x)
52
fromJResult _ (J.Ok x) = return x
53

  
54
-- | Tries to read a string from a JSON value.
55
--
56
-- In case the value was not a string, we fail the read (in the
57
-- context of the current monad.
58
readEitherString :: (Monad m) => J.JSValue -> m String
59
readEitherString v =
60
    case v of
61
      J.JSString s -> return $ J.fromJSString s
62
      _ -> fail "Wrong JSON type"
63

  
64
-- | Converts a JSON message into an array of JSON objects.
65
loadJSArray :: (Monad m)
66
               => String -- ^ Operation description (for error reporting)
67
               -> String -- ^ Input message
68
               -> m [J.JSObject J.JSValue]
69
loadJSArray s = fromJResult s . J.decodeStrict
70

  
71
-- | Reads the value of a key in a JSON object.
72
fromObj :: (J.JSON a, Monad m) => JSRecord -> String -> m a
73
fromObj o k =
74
    case lookup k o of
75
      Nothing -> fail $ printf "key '%s' not found, object contains only %s"
76
                 k (show (map fst o))
77
      Just val -> fromKeyValue k val
78

  
79
-- | Reads the value of an optional key in a JSON object.
80
maybeFromObj :: (J.JSON a, Monad m) =>
81
                JSRecord -> String -> m (Maybe a)
82
maybeFromObj o k =
83
    case lookup k o of
84
      Nothing -> return Nothing
85
      Just val -> liftM Just (fromKeyValue k val)
86

  
87
-- | Reads the value of a key in a JSON object with a default if missing.
88
fromObjWithDefault :: (J.JSON a, Monad m) =>
89
                      JSRecord -> String -> a -> m a
90
fromObjWithDefault o k d = liftM (fromMaybe d) $ maybeFromObj o k
91

  
92
-- | Reads a JValue, that originated from an object key.
93
fromKeyValue :: (J.JSON a, Monad m)
94
              => String     -- ^ The key name
95
              -> J.JSValue  -- ^ The value to read
96
              -> m a
97
fromKeyValue k val =
98
  fromJResult (printf "key '%s', value '%s'" k (show val)) (J.readJSON val)
99

  
100
-- | Small wrapper over readJSON.
101
fromJVal :: (Monad m, J.JSON a) => J.JSValue -> m a
102
fromJVal v =
103
    case J.readJSON v of
104
      J.Error s -> fail ("Cannot convert value '" ++ show v ++
105
                         "', error: " ++ s)
106
      J.Ok x -> return x
107

  
108
-- | Converts a JSON value into a JSON object.
109
asJSObject :: (Monad m) => J.JSValue -> m (J.JSObject J.JSValue)
110
asJSObject (J.JSObject a) = return a
111
asJSObject _ = fail "not an object"
112

  
113
-- | Coneverts a list of JSON values into a list of JSON objects.
114
asObjectList :: (Monad m) => [J.JSValue] -> m [J.JSObject J.JSValue]
115
asObjectList = mapM asJSObject
b/htools/Ganeti/HTools/Utils.hs
49 49
    , parseUnit
50 50
    ) where
51 51

  
52
import Control.Monad (liftM)
53 52
import Data.Char (toUpper)
54 53
import Data.List
55
import Data.Maybe (fromMaybe)
56 54
import qualified Text.JSON as J
57
import Text.Printf (printf)
58 55

  
59 56
import Debug.Trace
60 57

  
61 58
import Ganeti.HTools.Types
59
-- we will re-export these for our existing users
60
import Ganeti.HTools.JSON
62 61

  
63 62
-- * Debug functions
64 63

  
......
131 130
       -> a            -- ^ first result which has a True condition, or default
132 131
select def = maybe def snd . find fst
133 132

  
134
-- * JSON-related functions
135

  
136
-- | A type alias for the list-based representation of J.JSObject.
137
type JSRecord = [(String, J.JSValue)]
138

  
139
-- | Converts a JSON Result into a monadic value.
140
fromJResult :: Monad m => String -> J.Result a -> m a
141
fromJResult s (J.Error x) = fail (s ++ ": " ++ x)
142
fromJResult _ (J.Ok x) = return x
143

  
144
-- | Tries to read a string from a JSON value.
145
--
146
-- In case the value was not a string, we fail the read (in the
147
-- context of the current monad.
148
readEitherString :: (Monad m) => J.JSValue -> m String
149
readEitherString v =
150
    case v of
151
      J.JSString s -> return $ J.fromJSString s
152
      _ -> fail "Wrong JSON type"
153

  
154
-- | Converts a JSON message into an array of JSON objects.
155
loadJSArray :: (Monad m)
156
               => String -- ^ Operation description (for error reporting)
157
               -> String -- ^ Input message
158
               -> m [J.JSObject J.JSValue]
159
loadJSArray s = fromJResult s . J.decodeStrict
160

  
161
-- | Reads the value of a key in a JSON object.
162
fromObj :: (J.JSON a, Monad m) => JSRecord -> String -> m a
163
fromObj o k =
164
    case lookup k o of
165
      Nothing -> fail $ printf "key '%s' not found, object contains only %s"
166
                 k (show (map fst o))
167
      Just val -> fromKeyValue k val
168

  
169
-- | Reads the value of an optional key in a JSON object.
170
maybeFromObj :: (J.JSON a, Monad m) =>
171
                JSRecord -> String -> m (Maybe a)
172
maybeFromObj o k =
173
    case lookup k o of
174
      Nothing -> return Nothing
175
      Just val -> liftM Just (fromKeyValue k val)
176

  
177
-- | Reads the value of a key in a JSON object with a default if missing.
178
fromObjWithDefault :: (J.JSON a, Monad m) =>
179
                      JSRecord -> String -> a -> m a
180
fromObjWithDefault o k d = liftM (fromMaybe d) $ maybeFromObj o k
181

  
182
-- | Reads a JValue, that originated from an object key.
183
fromKeyValue :: (J.JSON a, Monad m)
184
              => String     -- ^ The key name
185
              -> J.JSValue  -- ^ The value to read
186
              -> m a
187
fromKeyValue k val =
188
  fromJResult (printf "key '%s', value '%s'" k (show val)) (J.readJSON val)
189 133

  
190 134
-- | Annotate a Result with an ownership information.
191 135
annotateResult :: String -> Result a -> Result a
......
201 145
           -> Result a
202 146
tryFromObj t o = annotateResult t . fromObj o
203 147

  
204
-- | Small wrapper over readJSON.
205
fromJVal :: (Monad m, J.JSON a) => J.JSValue -> m a
206
fromJVal v =
207
    case J.readJSON v of
208
      J.Error s -> fail ("Cannot convert value '" ++ show v ++
209
                         "', error: " ++ s)
210
      J.Ok x -> return x
211

  
212
-- | Converts a JSON value into a JSON object.
213
asJSObject :: (Monad m) => J.JSValue -> m (J.JSObject J.JSValue)
214
asJSObject (J.JSObject a) = return a
215
asJSObject _ = fail "not an object"
216

  
217
-- | Coneverts a list of JSON values into a list of JSON objects.
218
asObjectList :: (Monad m) => [J.JSValue] -> m [J.JSObject J.JSValue]
219
asObjectList = mapM asJSObject
220 148

  
221 149
-- * Parsing utility functions
222 150

  

Also available in: Unified diff