/** * BlueCove - Java library for Bluetooth * Copyright (C) 2008-2009 Michael Lifshits * Copyright (C) 2008-2009 Vlad Skarzhevskyy * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * @author vlads * @version $Id$ */ package com.intel.bluetooth.rmi; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.List; import java.util.Vector; public class Client { private static final String rmiRegistryHostDefault = "localhost"; private static final int rmiRegistryPortDefault = Server.rmiRegistryPortDefault; private static RemoteService remoteService; private static class ServiceProxy implements InvocationHandler { private AccessControlContext accessControlContext; private ServiceProxy() { accessControlContext = AccessController.getContext(); } public Object invoke(Object proxy, final Method m, Object[] args) throws Throwable { final ServiceRequest request = new ServiceRequest(m.getDeclaringClass().getCanonicalName(), m.getName(), m .getParameterTypes(), args); ServiceResponse response; try { response = AccessController.doPrivileged(new PrivilegedExceptionAction<ServiceResponse>() { public ServiceResponse run() throws RuntimeException { return execute(request, m); } }, accessControlContext); } catch (PrivilegedActionException e) { Throwable cause = e.getCause(); if (cause != null) { throw new RuntimeException(cause.getMessage(), cause); } else { throw e; } } if (response.getException() == null) { return response.getReturnValue(); } else { Throwable t = response.getException(); // Build combined StackTrace StackTraceElement[] remote = t.getStackTrace(); StackTraceElement[] curreent = Thread.currentThread().getStackTrace(); List<StackTraceElement> combined = new Vector<StackTraceElement>(); for (int i = 0; i < remote.length; i++) { combined.add(remote[i]); if ((remote[i].getMethodName().equals(m.getName())) && (remote[i].getClassName().startsWith(m.getDeclaringClass().getCanonicalName()))) { break; } } int startClient = curreent.length; for (int i = 0; i < curreent.length; i++) { if (curreent[i].getClassName().equals(this.getClass().getName())) { startClient = i + 1; break; } } for (int i = startClient; i < curreent.length; i++) { combined.add(curreent[i]); } t.setStackTrace(combined.toArray(new StackTraceElement[combined.size()])); throw t; } } } private static String getRemoteExceptionMessage(RemoteException e) { String message = e.getMessage(); int idx = message.indexOf("; nested exception is:"); if (idx != -1) { return message.substring(0, idx); } return message; } public synchronized static Object getService(Class<?> interfaceClass, boolean isMaster, String host, String port) throws RuntimeException { if (remoteService == null) { try { if (isMaster) { if ((host != null) && (!"localhost".equals(host))) { throw new IllegalArgumentException("Can't start RMI registry while connecting to remote host " + host); } Server.start(port); } remoteService = getRemoteService(host, port); remoteService.verify(interfaceClass.getCanonicalName()); } catch (RemoteException e) { Throwable t = (e.getCause() != null) ? e.getCause() : e; throw new RuntimeException(getRemoteExceptionMessage(e), t); } catch (NotBoundException e) { throw new RuntimeException(e.getMessage(), e); } } Class<?>[] allInterfaces = new Class[interfaceClass.getInterfaces().length + 1]; allInterfaces[0] = interfaceClass; System.arraycopy(interfaceClass.getInterfaces(), 0, allInterfaces, 1, interfaceClass.getInterfaces().length); return Proxy.newProxyInstance(interfaceClass.getClassLoader(), allInterfaces, new ServiceProxy()); } private static ServiceResponse execute(ServiceRequest request, Method method) throws RuntimeException { try { return remoteService.execute(request); } catch (RemoteException e) { Throwable t = (e.getCause() != null) ? e.getCause() : e; throw new RuntimeException(getRemoteExceptionMessage(e), t); } } private static RemoteService getRemoteService(String host, String port) throws RemoteException, NotBoundException { String rmiHost = rmiRegistryHostDefault; if ((host != null) && (host.length() > 0)) { rmiHost = host; } int rmiPort = rmiRegistryPortDefault; if ((port != null) && (port.length() > 0)) { rmiPort = Integer.parseInt(port); } if (rmiPort == 0) { // in process server return new RemoteServiceImpl(); } else { Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort); return (RemoteService) registry.lookup(RemoteService.SERVICE_NAME); } } }