1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.env.reflect.ProxyFactory; 18 import org.as2lib.env.reflect.InterfaceProxyFactory; 19 import org.as2lib.env.reflect.InvocationHandler; 20 import org.as2lib.io.conn.core.client.ClientServiceProxy; 21 import org.as2lib.io.conn.core.client.ClientServiceProxyFactory; 22 import org.as2lib.io.conn.core.client.AbstractClientServiceProxyFactory; 23 import org.as2lib.io.conn.local.client.SimpleClientServiceProxyFactory; 24 import org.as2lib.io.conn.core.event.MethodInvocationCallback; 25 26 /** 27 * {@code LocalClientServiceProxyFactory} acts as central provider of client service 28 * proxies. 29 * 30 * <p>This provision is in the simplest case just the returning of a new client 31 * service proxy. 32 * <code> 33 * var clientFactory:LocalClientServiceProxyFactory = new LocalClientServiceProxyFactory(); 34 * var client:ClientServiceProxy = clientFactory.getClientServiceProxy("local.as2lib.org/myService"); 35 * </code> 36 * 37 * <p>In a more complex case this means creating a client service proxy for a specific 38 * type, mostly an interface, that is the same type of the 'remote' service. 39 * <code> 40 * var clientFactory:LocalClientServiceProxyFactory = new LocalClientServiceProxyFactory(); 41 * var client:MyType = clientFactory.getClientServiceProxy("local.as2lib.org/myService", MyType); 42 * client.myMethod("myArg1", "myArg2"); 43 * </code> 44 * 45 * <p>There is sadly one flaw with the last type of usage. That is that the method 46 * cannot response directly due to the asynchronity of the call. To get a response 47 * you therefore have to pass a third argument of type {@code MethodInvocationCallback}. 48 * <code> 49 * var clientFactory:LocalClientServiceProxyFactory = new LocalClientServiceProxyFactory(); 50 * var client:MyType = clientFactory.getClientServiceProxy("local.as2lib.org/myService", MyType); 51 * var callback:MethodInvocationCallback = new MethodInvocationCallback(); 52 * client.myMethod("myArg1", "myArg2", callback); 53 * callback.onReturn = function(returnInfo:MethodInvocationReturnInfo):Void { 54 * trace("myMethod - return value: " + returnInfo.getReturnValue()); 55 * } 56 * callback.onError = function(errorInfo:MethodInvocationErrorInfo):Void { 57 * trace("myMethod - error: " + errorInfo.getException()); 58 * } 59 * </code> 60 * 61 * @author Simon Wacker 62 * @author Christoph Atteneder 63 * @see org.as2lib.io.conn.core.event.MethodInvocationCallback 64 */ 65 class org.as2lib.io.conn.local.client.LocalClientServiceProxyFactory extends AbstractClientServiceProxyFactory implements ClientServiceProxyFactory { 66 67 /** The currently used proxy factory to create proxies for a specific type. */ 68 private var typeProxyFactory:ProxyFactory; 69 70 /** Stores the client service proxy factory used to get client service proxy instances. */ 71 private var clientServiceProxyFactory:ClientServiceProxyFactory; 72 73 /** 74 * Constructs a new {@code LocalClientServiceProxyFactory} instance. 75 */ 76 public function LocalClientServiceProxyFactory(Void) { 77 } 78 79 /** 80 * Returns the currently used type proxy factory that is used to create proxies for 81 * a specific type. 82 * 83 * <p>That is either the proxy factory set via {@link #setTypeProxyFactory} 84 * or the default one, which is an instance of type {@link InterfaceProxyFactory}. 85 * 86 * <p>The default {@link InterfaceProxyFactory} can only be used to create proxies 87 * of interfaces. 88 * 89 * @return the currently used type proxy factory 90 */ 91 public function getTypeProxyFactory(Void):ProxyFactory { 92 if (!typeProxyFactory) typeProxyFactory = new InterfaceProxyFactory(); 93 return typeProxyFactory; 94 } 95 96 /** 97 * Sets the new type proxy factory that is used to create proxies for a specific type. 98 * 99 * <p>If you set a type proxy factory of value {@code null}, {@link #getTypeProxyFactory} 100 * will return the default factory. 101 * 102 * @param proxyFactory the new type proxy factory 103 */ 104 public function setTypeProxyFactory(typeServiceProxyFactory:ProxyFactory):Void { 105 this.typeProxyFactory = typeServiceProxyFactory; 106 } 107 108 /** 109 * Returns the client service proxy factory used to create client service proxy 110 * instances. 111 * 112 * <p>The returned factory is either the one set via {@link #setClientServiceProxyFactory} 113 * or the default one which is an instance of {@link SimpleClientServiceProxyFactory}. 114 * 115 * @return the currently used client service proxy factory 116 */ 117 public function getClientServiceProxyFactory(Void):ClientServiceProxyFactory { 118 if (!clientServiceProxyFactory) clientServiceProxyFactory = new SimpleClientServiceProxyFactory(); 119 return clientServiceProxyFactory; 120 } 121 122 /** 123 * Sets a new client service proxy factory used to get client service 124 * proxy instances. 125 * 126 * <p>If you set a new factory of value null or undefined {@link #getClientServiceProxyFactory} 127 * will return the default factory. 128 * 129 * @param clientServiceProxyFactory the new client service proxy factory 130 */ 131 public function setClientServiceProxyFactory(clientServiceProxyFactory:ClientServiceProxyFactory):Void { 132 this.clientServiceProxyFactory = clientServiceProxyFactory; 133 } 134 135 /** 136 * Returns a client service proxy for the service specified by the passed-in 137 * {@code url}. 138 * 139 * <p>You can use the returned proxy to invoke methods on the 'remote' service and 140 * to handle responses. 141 * 142 * @param url the url of the 'remote' service 143 * @return a client service proxy to invoke methods on the 'remote' service 144 */ 145 public function getClientServiceProxyByUrl(url:String):ClientServiceProxy { 146 return getClientServiceProxyFactory().getClientServiceProxy(url); 147 } 148 149 /** 150 * Returns a client service proxy that can be typed to the passed-in {@code type} 151 * (class or interface). 152 * 153 * <p>The type is therefore normally the type of the 'remote' service you wanna 154 * invoke methods on. 155 * 156 * <p>If {@code type} is {@code null}, an instance of type {@link ClientServiceProxy} 157 * will be returned. That means this method will then do the same as the 158 * {@link #getClientServiceProxyByUrl} method. 159 * 160 * <p>Note that with the default configuration only interfaces can be used as 161 * {@code type}. You can edit this behavior through the {@link #setTypeProxyFactory}. 162 * method. 163 * 164 * @param url the url of the 'remote' service 165 * @param type the type of the 'remote' service 166 * @return a client service proxy that can be casted to the passed-in {@code type} 167 */ 168 public function getClientServiceProxyByUrlAndType(url:String, type:Function) { 169 var serviceProxy:ClientServiceProxy = getClientServiceProxyByUrl(url); 170 if (!type) return serviceProxy; 171 var handler:InvocationHandler = getBlankInvocationHandler(); 172 handler.invoke = function(proxy, methodName:String, args:Array) { 173 if (args[args.length-1] instanceof MethodInvocationCallback) { 174 var callback:MethodInvocationCallback = MethodInvocationCallback(args.pop()); 175 return serviceProxy.invokeByNameAndArgumentsAndCallback(methodName, args, callback); 176 } else { 177 return serviceProxy.invokeByNameAndArguments(methodName, args); 178 } 179 }; 180 return getTypeProxyFactory().createProxy(type, handler); 181 } 182 183 /** 184 * Returns a blank invocation handler. This is a handler with no methods implemented. 185 * 186 * @return a blank invocation handler 187 */ 188 private function getBlankInvocationHandler(Void):InvocationHandler { 189 var result = new Object(); 190 result.__proto__ = InvocationHandler["prototype"]; 191 result.__constructor__ = InvocationHandler; 192 return result; 193 } 194 195 }