/*
* Copyright 2014 NAVER Corp.
*
* 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 com.navercorp.pinpoint.bootstrap;
import java.util.concurrent.Callable;
/**
* This template is used for changing the current thread's classloader to the assigned one and executing a callable.
*
* @author emeroad
*/
public class ContextClassLoaderExecuteTemplate<V> {
private final ClassLoader classLoader;
public ContextClassLoaderExecuteTemplate(ClassLoader classLoader) {
if (classLoader == null) {
throw new NullPointerException("classLoader must not be null");
}
this.classLoader = classLoader;
}
public V execute(Callable<V> callable) throws BootStrapException {
try {
final Thread currentThread = Thread.currentThread();
final ClassLoader before = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(ContextClassLoaderExecuteTemplate.this.classLoader);
try {
return callable.call();
} finally {
// even though the "BEFORE" classloader is null, rollback is needed.
// if an exception occurs BEFORE callable.call(), the call flow can't reach here.
// so rollback here is right.
currentThread.setContextClassLoader(before);
}
} catch (BootStrapException ex){
throw ex;
} catch (Exception ex) {
throw new BootStrapException("execute fail. Error:" + ex.getMessage(), ex);
}
}
}