----------------------------------------------------------------------------- -- Copyright 2015, Ideas project team. This file is distributed under the -- terms of the Apache License 2.0. For more information, see the files -- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ----------------------------------------------------------------------------- -- | -- Maintainer : bastiaan.heeren@ou.nl -- Stability : provisional -- Portability : portable (depends on ghc) -- -- Services using XML notation -- ----------------------------------------------------------------------------- -- $Id: ModeXML.hs 8743 2015-10-14 19:48:13Z bastiaan $ module Ideas.Encoding.ModeXML (processXML) where import Control.Exception import Control.Monad import Data.Maybe import Ideas.Common.Library hiding (exerciseId, (:=)) import Ideas.Common.Utils (Some(..), timedSeconds) import Ideas.Encoding.DecoderXML import Ideas.Encoding.Encoder (makeOptions) import Ideas.Encoding.EncoderHTML import Ideas.Encoding.EncoderXML import Ideas.Encoding.Evaluator import Ideas.Main.Logging (LogRef, changeLog, errormsg) import Ideas.Service.DomainReasoner import Ideas.Service.Request import Ideas.Text.HTML import Ideas.Text.XML import Prelude hiding (catch) import System.IO.Error hiding (catch) processXML :: Maybe Int -> Maybe String -> DomainReasoner -> LogRef -> String -> IO (Request, String, String) processXML maxTime cgiBin dr logRef input = do xml <- either fail return (parseXML input) req <- xmlRequest cgiBin xml resp <- maybe id timedSeconds maxTime (xmlReply dr logRef req xml) `catch` handler let showXML | compactOutput req = compactXML | otherwise = show if htmlOutput req then return (req, showXML resp, "text/html") else let out = addVersion (version dr) resp in return (req, showXML out, "application/xml") where handler :: IOException -> IO XML handler = resultError logRef . ioeGetErrorString addVersion :: String -> XML -> XML addVersion s xml = let info = [ "version" := s ] in xml { attributes = attributes xml ++ info } xmlRequest :: Monad m => Maybe String -> XML -> m Request xmlRequest cgiBin xml = do unless (name xml == "request") $ fail "expected xml tag request" enc <- case findAttribute "encoding" xml of Just s -> readEncoding s Nothing -> return [] return emptyRequest { serviceId = fmap newId $ findAttribute "service" xml , exerciseId = extractExerciseId xml , source = findAttribute "source" xml , cgiBinary = cgiBin , requestInfo = findAttribute "requestinfo" xml , logSchema = findAttribute "logging" xml >>= readSchema , feedbackScript = findAttribute "script" xml , dataformat = XML , encoding = enc } xmlReply :: DomainReasoner -> LogRef -> Request -> XML -> IO XML xmlReply dr logRef request xml = do srv <- case serviceId request of Just a -> findService dr a Nothing -> fail "No service" Some options <- makeOptions dr request if htmlOutput request -- HTML evaluator then liftM toXML $ evalService logRef options (htmlEvaluator dr) srv xml -- xml evaluator else liftM resultOk $ evalService logRef options xmlEvaluator srv xml extractExerciseId :: Monad m => XML -> m Id extractExerciseId = liftM newId . findAttribute "exerciseid" resultOk :: XMLBuilder -> XML resultOk body = makeXML "reply" $ ("result" .=. "ok") <> body resultError :: LogRef -> String -> IO XML resultError logRef msg = do changeLog logRef (\r -> r {errormsg = msg}) return $ makeXML "reply" $ ("result" .=. "error") <> tag "message" (string msg) ------------------------------------------------------------ xmlEvaluator :: Evaluator a XML XMLBuilder xmlEvaluator = Evaluator xmlDecoder xmlEncoder htmlEvaluator :: DomainReasoner -> Evaluator a XML HTMLPage htmlEvaluator dr = Evaluator xmlDecoder (htmlEncoder dr)