/* * 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. */ package org.apache.aries.async.impl; import java.lang.reflect.Method; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import org.apache.aries.async.promise.PromiseImpl; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceException; import org.osgi.framework.ServiceReference; import org.osgi.service.async.delegate.AsyncDelegate; import org.osgi.service.log.LogService; import org.osgi.util.promise.Failure; import org.osgi.util.promise.Promise; import org.osgi.util.tracker.ServiceTracker; public class MethodCall { private final Bundle clientBundle; private final ServiceTracker<LogService, LogService> logServiceTracker; private final ServiceReference<?> reference; private final Object service; final Method method; final Object[] arguments; public MethodCall(Bundle clientBundle, ServiceTracker<LogService, LogService> logServiceTracker, ServiceReference<?> reference, Object service, Method method, Object[] arguments) { this.clientBundle = clientBundle; this.logServiceTracker = logServiceTracker; this.reference = reference; this.service = service; this.method = method; this.arguments = arguments; } Object getService() { if(reference != null) { BundleContext bc = clientBundle.getBundleContext(); if(bc != null) { try { Object svc = bc.getService(reference); if(svc == null) { throw new ServiceException("Unable to retrieve the mediated service because it has been unregistered", 7); } else { return svc; } } catch (Exception e) { throw new ServiceException("Unable to retrieve the mediated service", 7, e); } } else { throw new ServiceException("Unable to retrieve the mediated service because the client bundle has been stopped", 7); } } else { return service; } } void releaseService() { if(reference != null) { BundleContext bc = clientBundle.getBundleContext(); if(bc != null) { bc.ungetService(reference); } } } public <V> Promise<V> invokeAsynchronously(Bundle clientBundle, ExecutorService executor, ScheduledExecutorService ses) { PromiseImpl<V> promiseImpl = new PromiseImpl<V>(executor, ses); Object svc; try { svc = getService(); } catch (Exception e) { promiseImpl.fail(e); return promiseImpl; } if(svc instanceof AsyncDelegate) { try { @SuppressWarnings("unchecked") Promise<V> p = (Promise<V>) ((AsyncDelegate) svc).async(method, arguments); if(p != null) { try { promiseImpl.resolveWith(p); return promiseImpl; } finally { releaseService(); } } } catch (Exception e) { try { promiseImpl.fail(e); return promiseImpl; } finally { releaseService(); } } } //If we get here then svc is either not an async delegate, or it rejected the call try { executor.execute(new Work<V>(this, promiseImpl)); } catch (RejectedExecutionException ree) { promiseImpl.fail(new ServiceException("The Async service is unable to accept new requests", 7, ree)); } //Release the service we got at the start of this method promiseImpl.onResolve(new Runnable() { public void run() { releaseService(); } }); return promiseImpl; } public Promise<Void> fireAndForget(Bundle clientBundle, ExecutorService executor, ScheduledExecutorService ses) { PromiseImpl<Void> started = new PromiseImpl<Void>(executor, ses); Object svc; try { svc = getService(); } catch (Exception e) { logError("Unable to obtain the service object", e); started.fail(e); return started; } if(svc instanceof AsyncDelegate) { try { if(((AsyncDelegate) svc).execute(method, arguments)) { releaseService(); started.resolve(null); return started; } } catch (Exception e) { releaseService(); logError("The AsyncDelegate rejected the fire-and-forget invocation with an exception", e); started.fail(e); return started; } } //If we get here then svc is either not an async delegate, or it rejected the call PromiseImpl<Void> cleanup = new PromiseImpl<Void>(); try { executor.execute(new FireAndForgetWork(this, cleanup, started)); cleanup.onResolve(new Runnable() { public void run() { releaseService(); } }).then(null, new Failure(){ public void fail(Promise<?> resolved) throws Exception { logError("The fire-and-forget invocation failed", resolved.getFailure()); } }); } catch (RejectedExecutionException ree) { logError("The Async Service threadpool rejected the fire-and-forget invocation", ree); started.fail(new ServiceException("Unable to enqueue the fire-and forget task", 7, ree)); } return started; } void logError(String message, Throwable e) { for(LogService log : logServiceTracker.getServices(new LogService[0])) { if(reference == null) { log.log(LogService.LOG_ERROR, message, e); } else { log.log(reference, LogService.LOG_ERROR, message, e); } } } }