View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2008 Michael Lifshits
4    *  Copyright (C) 2008 Vlad Skarzhevskyy
5    *
6    *  Licensed to the Apache Software Foundation (ASF) under one
7    *  or more contributor license agreements.  See the NOTICE file
8    *  distributed with this work for additional information
9    *  regarding copyright ownership.  The ASF licenses this file
10   *  to you under the Apache License, Version 2.0 (the
11   *  "License"); you may not use this file except in compliance
12   *  with the License.  You may obtain a copy of the License at
13   *
14   *    http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing,
17   *  software distributed under the License is distributed on an
18   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   *  KIND, either express or implied.  See the License for the
20   *  specific language governing permissions and limitations
21   *  under the License.
22   *
23   *  @author vlads
24   *  @version $Id: Client.java 2471 2008-12-01 03:44:20Z skarzhevskyy $
25   */
26  package com.intel.bluetooth.rmi;
27  
28  import java.lang.reflect.InvocationHandler;
29  import java.lang.reflect.Method;
30  import java.lang.reflect.Proxy;
31  import java.rmi.NotBoundException;
32  import java.rmi.RemoteException;
33  import java.rmi.registry.LocateRegistry;
34  import java.rmi.registry.Registry;
35  import java.security.AccessControlContext;
36  import java.security.AccessController;
37  import java.security.PrivilegedActionException;
38  import java.security.PrivilegedExceptionAction;
39  import java.util.List;
40  import java.util.Vector;
41  
42  public class Client {
43  
44  	private static final String rmiRegistryHostDefault = "localhost";
45  
46  	private static final int rmiRegistryPortDefault = Server.rmiRegistryPortDefault;
47  
48  	private static RemoteService remoteService;
49  
50  	private static class ServiceProxy implements InvocationHandler {
51  
52  		private AccessControlContext accessControlContext;
53  
54  		private ServiceProxy() {
55  			accessControlContext = AccessController.getContext();
56  		}
57  
58  		public Object invoke(Object proxy, final Method m, Object[] args) throws Throwable {
59  			final ServiceRequest request = new ServiceRequest(m.getDeclaringClass().getCanonicalName(), m.getName(), m
60  					.getParameterTypes(), args);
61  			ServiceResponse response;
62  			try {
63  				response = AccessController.doPrivileged(new PrivilegedExceptionAction<ServiceResponse>() {
64  					public ServiceResponse run() throws RuntimeException {
65  						return execute(request, m);
66  					}
67  				}, accessControlContext);
68  			} catch (PrivilegedActionException e) {
69  				Throwable cause = e.getCause();
70  				if (cause != null) {
71  					throw new RuntimeException(cause.getMessage(), cause);
72  				} else {
73  					throw e;
74  				}
75  			}
76  			if (response.getException() == null) {
77  				return response.getReturnValue();
78  			} else {
79  				Throwable t = response.getException();
80  				// Build combined StackTrace
81  				StackTraceElement[] remote = t.getStackTrace();
82  				StackTraceElement[] curreent = Thread.currentThread().getStackTrace();
83  				List<StackTraceElement> combined = new Vector<StackTraceElement>();
84  				for (int i = 0; i < remote.length; i++) {
85  					combined.add(remote[i]);
86  					if ((remote[i].getMethodName().equals(m.getName()))
87  							&& (remote[i].getClassName().startsWith(m.getDeclaringClass().getCanonicalName()))) {
88  						break;
89  					}
90  				}
91  				int startClient = curreent.length;
92  				for (int i = 0; i < curreent.length; i++) {
93  					if (curreent[i].getClassName().equals(this.getClass().getName())) {
94  						startClient = i + 1;
95  						break;
96  					}
97  				}
98  				for (int i = startClient; i < curreent.length; i++) {
99  					combined.add(curreent[i]);
100 				}
101 				t.setStackTrace(combined.toArray(new StackTraceElement[combined.size()]));
102 				throw t;
103 			}
104 		}
105 	}
106 
107 	private static String getRemoteExceptionMessage(RemoteException e) {
108 		String message = e.getMessage();
109 		int idx = message.indexOf("; nested exception is:");
110 		if (idx != -1) {
111 			return message.substring(0, idx);
112 		}
113 		return message;
114 	}
115 
116 	public synchronized static Object getService(Class<?> interfaceClass, boolean isMaster, String host, String port)
117 			throws RuntimeException {
118 		if (remoteService == null) {
119 			try {
120 				if (isMaster) {
121 					if ((host != null) && (!"localhost".equals(host))) {
122 						throw new IllegalArgumentException("Can't start RMI registry while connecting to remote host "
123 								+ host);
124 					}
125 					Server.start(port);
126 				}
127 				remoteService = getRemoteService(host, port);
128 				remoteService.verify(interfaceClass.getCanonicalName());
129 			} catch (RemoteException e) {
130 				Throwable t = (e.getCause() != null) ? e.getCause() : e;
131 				throw new RuntimeException(getRemoteExceptionMessage(e), t);
132 			} catch (NotBoundException e) {
133 				throw new RuntimeException(e.getMessage(), e);
134 			}
135 		}
136 		Class<?>[] allInterfaces = new Class[interfaceClass.getInterfaces().length + 1];
137 		allInterfaces[0] = interfaceClass;
138 		System.arraycopy(interfaceClass.getInterfaces(), 0, allInterfaces, 1, interfaceClass.getInterfaces().length);
139 		return Proxy.newProxyInstance(interfaceClass.getClassLoader(), allInterfaces, new ServiceProxy());
140 	}
141 
142 	private static ServiceResponse execute(ServiceRequest request, Method method) throws RuntimeException {
143 		try {
144 			return remoteService.execute(request);
145 		} catch (RemoteException e) {
146 			Throwable t = (e.getCause() != null) ? e.getCause() : e;
147 			throw new RuntimeException(getRemoteExceptionMessage(e), t);
148 		}
149 	}
150 
151 	private static RemoteService getRemoteService(String host, String port) throws RemoteException, NotBoundException {
152 		String rmiHost = rmiRegistryHostDefault;
153 		if ((host != null) && (host.length() > 0)) {
154 			rmiHost = host;
155 		}
156 		int rmiPort = rmiRegistryPortDefault;
157 		if ((port != null) && (port.length() > 0)) {
158 			rmiPort = Integer.parseInt(port);
159 		}
160 		if (rmiPort == 0) {
161 			// in process server
162 			return new RemoteServiceImpl();
163 		} else {
164 			Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort);
165 			return (RemoteService) registry.lookup(RemoteService.SERVICE_NAME);
166 		}
167 	}
168 }