PageRenderTime 55ms CodeModel.GetById 16ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

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