X-Git-Url: http://nitlanguage.org diff --git a/src/nitrestful.nit b/src/nitrestful.nit index 2b118a3..6a93f30 100644 --- a/src/nitrestful.nit +++ b/src/nitrestful.nit @@ -23,7 +23,7 @@ private class RestfulPhase super Phase # Classes with methods marked with the `restful` annotation - var restful_classes = new HashSet[MClass] + var restful_classes = new HashSet[MClassDef] redef fun process_annotated_node(node, nat) do @@ -37,6 +37,12 @@ private class RestfulPhase return end + var mpropdef = node.mpropdef + if mpropdef == null then return + var mproperty = mpropdef.mproperty + var mclassdef = mpropdef.mclassdef + var mmodule = mclassdef.mmodule + var http_resources = new Array[String] var http_methods = new Array[String] for arg in nat.n_args do @@ -48,6 +54,8 @@ private class RestfulPhase else if arg isa ATypeExpr and not id.chars.has("[") then # Class id -> HTTP method http_methods.add id + else if id == "async" then + mproperty.restful_async = true else toolcontext.error(nat.location, "Syntax Error: `restful` expects String literals or ids as arguments.") @@ -55,13 +63,6 @@ private class RestfulPhase end end - var mpropdef = node.mpropdef - if mpropdef == null then return - - var mproperty = mpropdef.mproperty - var mclassdef = mpropdef.mclassdef - var mmodule = mclassdef.mmodule - # Test subclass of `RestfulAction` var sup_class_name = "RestfulAction" var sup_class = toolcontext.modelbuilder.try_get_mclass_by_name( @@ -76,16 +77,15 @@ private class RestfulPhase end # Register the property - var mclass = mclassdef.mclass - mclass.restful_methods.add mproperty - restful_classes.add mclass + mclassdef.restful_methods.add mproperty + restful_classes.add mclassdef if http_resources.not_empty then mproperty.restful_resources = http_resources mproperty.restful_verbs = http_methods end end -redef class MClass +redef class MClassDef # Methods with the `restful` annotation in this class private var restful_methods = new Array[MMethod] @@ -97,6 +97,9 @@ redef class MMethod # Associated resources within an action, e.g. `foo` in `http://localhost/foo?arg=bar` private var restful_resources: Array[String] = [name] is lazy + + # Is this a `restful` method to be executed asynchronously + private var restful_async = false end redef class ToolContext @@ -128,7 +131,7 @@ redef class MType else # Deserialize everything else template.add """ - var out_{{{arg_name}}} = deserialize_arg(in_{{{arg_name}}}) + var out_{{{arg_name}}} = deserialize_arg(in_{{{arg_name}}}, "{{{self.name}}}") """ end end @@ -190,6 +193,7 @@ else end var nit_module = new NitModule(module_name) +nit_module.annotations.add """generated""" nit_module.annotations.add """no_warning("parentheses")""" nit_module.header = """ # This file is generated by nitrestful @@ -203,11 +207,15 @@ end var phase = toolcontext.restful_phase assert phase isa RestfulPhase -for mclass in phase.restful_classes do +for mclassdef in phase.restful_classes do + var mclass = mclassdef.mclass var t = new Template nit_module.content.add t + var classes = new Template + nit_module.content.add classes + t.add """ redef class {{{mclass}}} redef fun prepare_respond_and_close(request, truncated_uri, http_server) @@ -222,7 +230,7 @@ redef class {{{mclass}}} var resource = resources.first """ - var methods = mclass.restful_methods + var methods = mclassdef.restful_methods for i in methods.length.times, method in methods do var msig = method.intro.msignature if msig == null then continue @@ -256,7 +264,11 @@ redef class {{{mclass}}} """ var mtype = param.mtype - mtype.gen_arg_convert(t, param.name) + var bound_mtype = mclassdef.bound_mtype + var resolved_mtype = mtype.resolve_for(bound_mtype, bound_mtype, mclassdef.mmodule, true) + var resolved_type_name = resolved_mtype.name + + resolved_mtype.gen_arg_convert(t, param.name) var arg = "out_{param.name}" args.add arg @@ -275,12 +287,50 @@ redef class {{{mclass}}} var sig = "" if args.not_empty then sig = "({args.join(", ")})" - t.add """ + if not method.restful_async then + # Synchronous method + t.add """ var response = {{{method.name}}}{{{sig}}} http_server.respond response http_server.close return """ + else + # Asynchronous method + var task_name = "Task_{mclass}_{method.name}" + args.unshift "http_server" + args.unshift "request" + args.unshift "self" + + t.add """ + var task = new {{{task_name}}}({{{args.join(", ")}}}) + self.thread_pool.execute task + return +""" + + var thread_attribs = new Array[String] + for param in msig.mparameters do + thread_attribs.add """ + private var out_{{{param.name}}}: {{{param.mtype}}}""" + end + + classes.add """ + +# Generated task to execute {{{mclass}}}::{{{method.name}}} +class {{{task_name}}} + super RestfulTask + + redef type A: {{{mclass}}} + +{{{thread_attribs.join("\n")}}} + + redef fun indirect_restful_method + do + return action.{{{method.name}}}{{{sig}}} + end +end +""" + end if isas.not_empty then t.add """ end