/* * Copyright 2011 Toni Menzel. * * Licensed 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.ops4j.pax.exam.rbc.client.intern; import java.io.InputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.NoSuchObjectException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.ops4j.pax.exam.ExceptionHelper; import org.ops4j.pax.exam.RelativeTimeout; import org.ops4j.pax.exam.TestAddress; import org.ops4j.pax.exam.rbc.client.RemoteBundleContextClient; /** * */ public class RetryRemoteBundleContextClient implements RemoteBundleContextClient { private static final Logger LOG = LoggerFactory.getLogger(RetryRemoteBundleContextClient.class); private static final int RETRY_WAIT = 500; private final RemoteBundleContextClient proxy; private final int maxRetry; public RetryRemoteBundleContextClient(final RemoteBundleContextClient client, int maxRetries) { maxRetry = maxRetries; proxy = (RemoteBundleContextClient) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { RemoteBundleContextClient.class }, new InvocationHandler() { // CHECKSTYLE:SKIP : InvocationHandler API public Object invoke(Object o, Method method, Object[] objects) throws Throwable { Object ret = null; Exception lastError = null; // invoke x times or fail. boolean retry = false; int triedTimes = 0; do { try { LOG.debug("Call RBC." + method.getName() + " (retries: " + triedTimes + ")"); triedTimes++; if (retry) { Thread.sleep(RETRY_WAIT); } ret = method.invoke(client, objects); retry = false; } // CHECKSTYLE:SKIP catch (Exception ex) { lastError = ex; Throwable cause = ExceptionHelper.unwind(ex); boolean contain = ExceptionHelper.hasThrowable(ex, NoSuchObjectException.class); if (contain) { LOG.warn("Catched (rooted) " + cause.getClass().getName() + " in RBC." + method.getName()); retry = true; } else { LOG.debug("Exception that does not cause Retry : (rooted) " + cause.getClass().getName() + " in RBC." + method.getName(), cause); // just escape throw lastError; } } } while (retry && maxRetry > triedTimes); // check if we need to throw an exception: if ((retry) && (lastError != null)) { throw new Exception(lastError); } LOG.debug("Return RBC." + method.getName() + " with: " + ret); return ret; } }); } public long install(String location, InputStream stream) { return proxy.install(location, stream); } public void cleanup() { proxy.cleanup(); } public void setBundleStartLevel(long bundleId, int startLevel) { proxy.setBundleStartLevel(bundleId, startLevel); } public void start() { proxy.start(); } public void stop() { proxy.stop(); } public void waitForState(long bundleId, int state, RelativeTimeout timeout) { proxy.waitForState(bundleId, state, timeout); } public void call(TestAddress address) { proxy.call(address); } @Override public void uninstall(long bundleId) { proxy.uninstall(bundleId); } }