/razweb/src/com/razie/pub/lightsoa/HttpSoaBinding.java

http://razpub.googlecode.com/ · Java · 255 lines · 162 code · 27 blank · 66 comment · 57 complexity · 062a189eb6c380f24219bfca47904b52 MD5 · raw file

  1. /**
  2. * Razvan's code. Copyright 2008 based on Apache (share alike) see LICENSE.txt for details.
  3. */
  4. package com.razie.pub.lightsoa;
  5. import java.io.IOException;
  6. import java.lang.reflect.Method;
  7. import java.util.Properties;
  8. import razie.base.AttrAccess;
  9. import razie.base.AttrAccessImpl;
  10. import razie.base.ScriptContext;
  11. import razie.draw.DrawStream;
  12. import razie.draw.HttpDrawStream;
  13. import razie.draw.JsonDrawStream;
  14. import razie.draw.MimeDrawStream;
  15. import razie.draw.SimpleDrawStream;
  16. import razie.draw.Technology;
  17. import razie.g.GRef;
  18. import com.razie.pub.base.data.HttpUtils;
  19. import com.razie.pub.base.log.Log;
  20. import com.razie.pub.comms.MyServerSocket;
  21. import com.razie.pub.http.SoaNotHtml;
  22. import com.razie.pub.http.StreamConsumedReply;
  23. /**
  24. * call services or assets via simple http requests
  25. *
  26. * can handle methods that take only String arguments, including SoaStreamables, which return one
  27. * of: void, String, Drawable, Object - the return value will be drawn on an HttpDrawStream
  28. *
  29. * use SoaNotHtml to prevent the return String from being drawn on html...
  30. *
  31. * as a rule of thumb in implementing these, the URLs are of the form /PREFIX/serviceName/METHODNAME
  32. *
  33. * @author razvanc99
  34. */
  35. public class HttpSoaBinding extends SoaBinding {
  36. /**
  37. * create a simple binding for a service instance - you then have to register it with the server
  38. *
  39. * if the class is annotated, use the other constructor, please...
  40. *
  41. * @param service the object implementing the service methods
  42. * @param serviceName the name to use - no funky characters, other than ".". Especially no
  43. * spaces, eh?
  44. */
  45. public HttpSoaBinding(Object service, String serviceName) {
  46. this(service.getClass(), serviceName);
  47. this.service = service;
  48. }
  49. /**
  50. * create a simple binding - you then have to register it with the server
  51. *
  52. * if the class is annotated, use the other constructor, please...
  53. *
  54. * @param service the class of the callback implementing the service/asset methods
  55. * @param serviceName the name to use - no funky characters, other than ".". Especially no
  56. * spaces, eh?
  57. */
  58. public HttpSoaBinding(Class<?> serviceCls, String serviceName) {
  59. super(serviceCls, serviceName);
  60. // check service name matches annotation
  61. if (serviceCls != null && serviceCls.getAnnotation(SoaService.class) != null) {
  62. SoaService s = (SoaService) serviceCls.getAnnotation(SoaService.class);
  63. if (!s.name().equals(serviceName))
  64. throw new IllegalArgumentException(
  65. "can't bind @SoaService/@SoaAsset with wrong name: "
  66. + service.getClass().getName());
  67. } else if (serviceCls != null && serviceCls.getAnnotation(SoaAsset.class) != null) {
  68. SoaAsset s = (SoaAsset) serviceCls.getAnnotation(SoaAsset.class);
  69. String debug = s.meta();
  70. if (s.meta().length() > 0 && !s.meta().equals(serviceName))
  71. throw new IllegalArgumentException(
  72. "can't bind @SoaService/@SoaAsset with wrong name: "
  73. + serviceCls.getName());
  74. } else {
  75. logger.log("WARN_HTTP_BOUND class which was not annotated: "
  76. + (serviceCls == null ? "null" : serviceCls.getName()));
  77. }
  78. }
  79. /**
  80. * create a simple binding for and annotated SoaService - you then have to register it wiht the
  81. * server
  82. *
  83. * @param service the object implementing the service methods
  84. * @param serviceName the name to use - no funky characters, other than ".". Especially no
  85. * spaces, eh?
  86. */
  87. public HttpSoaBinding(Object service) {
  88. super(service, "");
  89. if (service.getClass().getAnnotation(SoaService.class) != null) {
  90. SoaService s = (SoaService) service.getClass().getAnnotation(SoaService.class);
  91. this.serviceName = s.name();
  92. } else {
  93. throw new IllegalArgumentException("can't bind service not annotated with @SoaService: "
  94. + service.getClass().getName());
  95. }
  96. }
  97. /**
  98. * main entry point from the http server
  99. *
  100. * @param actionName the command code == soa method name
  101. * @param protocol protocol normaly "http"
  102. * @param cmdargs args in the url following the method name with, think servlet entry point
  103. * "mymethod/a/b"
  104. * @param parms all parms in the url decoded parms follow the url with ? and &
  105. * @param socket the server socket
  106. * @return
  107. */
  108. public Object execServer(String actionName, String protocol, String cmdargs, Properties parms,
  109. MyServerSocket socket) {
  110. Object otoi = this.service;
  111. GRef key = null;
  112. Method method = null;
  113. if (otoi == null) {
  114. // must be an asset instance
  115. if (actionName.startsWith(razie.G$.MODULE$.RAZIE())) {
  116. key = razie.g.GRef$.MODULE$.parse(HttpUtils.fromUrlEncodedString(actionName));
  117. // if (actionName.startsWith(AssetKey$.MODULE$.PREFIX())) {
  118. // key = AssetKey$.MODULE$.fromString(HttpUtils.fromUrlEncodedString(actionName));
  119. String[] ss = cmdargs.split("/", 2);
  120. actionName = ss[0];
  121. cmdargs = ss.length > 1 ? ss[1] : null;
  122. } else {
  123. String[] ss = cmdargs.split("/", 3);
  124. // key = new AssetKey(actionName, HttpUtils.fromUrlEncodedString(ss[0]),null);
  125. key = razie.g.GRef$.MODULE$.id(actionName, HttpUtils.fromUrlEncodedString(ss[0]),null);
  126. // by default actionName would be "details"
  127. actionName = ss.length > 1 ? ss[1] : "details";
  128. cmdargs = ss.length > 2 ? ss[2] : null;
  129. }
  130. otoi = razie.g.GAMResolver$.MODULE$.resolve(key);
  131. }
  132. if (otoi == null) {
  133. logger.trace(1, "HTTP_SOA_ASSETNOTFOUND: " + key);
  134. return "HTTP_SOA_ASSETNOTFOUND: " + key;
  135. }
  136. Object response = null;
  137. DrawStream out = null;
  138. // this section used to test performance...
  139. // if (true) response = "dudu";
  140. // else
  141. if (methods.size() <= 0) {
  142. // didn't find it but there's no methods for this anyhow...
  143. logger.trace(1, "HTTP_SOA_delegateTo_AssetMgr.doAction: " + actionName + ": ");
  144. ScriptContext ctx = new ScriptContext.Impl(ScriptContext.Impl.global());
  145. ctx.setAttr(parms);
  146. response = razie.g.GAMAct$.MODULE$.act(key, actionName, ctx);
  147. } else {
  148. if (methods.containsKey(actionName)) {
  149. method = methods.get(actionName);
  150. } else if (sink != null) {
  151. method = sink;
  152. } else if (methods.size() > 0 && !methods.containsKey(actionName)) {
  153. logger.log("HTTP_SOA_UNKWNOWNACTION: " + actionName);
  154. return "HTTP_SOA_UNKNOWNACTION: " + actionName;
  155. }
  156. if (method != null) {
  157. logger.trace(1, "HTTP_SOA_" + actionName + ": ");
  158. AttrAccess args = new AttrAccessImpl(parms);
  159. // setup the parms
  160. SoaMethod mdesc = method.getAnnotation(SoaMethod.class);
  161. socket.auth(mdesc.perm());
  162. if (method.getAnnotation(SoaStreamable.class) != null) {
  163. SoaStreamable nh = method.getAnnotation(SoaStreamable.class);
  164. if (nh.mime().length() > 0) {
  165. out = makeMimeDrawStream(socket, nh.mime());
  166. } else
  167. out = makeDrawStream(socket, protocol);
  168. response = invokeStreamable(otoi, actionName, out, args);
  169. } else {
  170. response = invoke(otoi, actionName, args);
  171. }
  172. if (method.getAnnotation(SoaNotHtml.class) != null) {
  173. if (method.getAnnotation(SoaStreamable.class) != null) {
  174. throw new IllegalArgumentException("Cannot have a streamable nothtml");
  175. }
  176. // no special formatting, probably defaults to toString()
  177. return response;
  178. }
  179. }
  180. }
  181. if (response != null) {
  182. // maybe stream already created for a streamable that returned a Drawable?
  183. // unbelievable...
  184. out = out != null ? out : makeDrawStream(socket, protocol);
  185. out.write(response);
  186. out.close();
  187. return new StreamConsumedReply();
  188. } else if (response == null) {
  189. if (out != null)
  190. out.close();
  191. return new StreamConsumedReply();
  192. }
  193. return response;
  194. }
  195. protected DrawStream makeDrawStream(MyServerSocket socket, String protocol) {
  196. DrawStream out;
  197. try {
  198. if ("http".equals(protocol))
  199. out = new HttpDrawStream(socket.from, socket.getOutputStream());
  200. else if ("json".equals(protocol))
  201. out = new JsonDrawStream(socket);
  202. else
  203. out = new SimpleDrawStream(Technology.TEXT, socket.getOutputStream());
  204. } catch (IOException e2) {
  205. throw new RuntimeException(e2);
  206. }
  207. return out;
  208. }
  209. protected DrawStream makeMimeDrawStream(MyServerSocket socket, String mime) {
  210. DrawStream out;
  211. try {
  212. if (HttpDrawStream.MIME_TEXT_HTML.equals(mime))
  213. out = new HttpDrawStream(socket.from, socket.getOutputStream());
  214. else if (JsonDrawStream.MIME_APPLICATION_JSON.equals(mime))
  215. out = new JsonDrawStream(socket);
  216. else
  217. out = new MimeDrawStream(socket.getOutputStream(), mime);
  218. } catch (IOException e2) {
  219. throw new RuntimeException(e2);
  220. }
  221. return out;
  222. }
  223. public String toString() {
  224. return this.serviceName + " : "
  225. + (this.service == null ? "NULL SERVICE - probably the asset service?" : this.service.getClass().getName());
  226. }
  227. private static final Log logger = Log.create("http", HttpSoaBinding.class.getName());
  228. }