| /* |
| * 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 WARRANTIESOR 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.jpa.container.parser.impl; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.reflect.UndeclaredThrowableException; |
| import java.net.URL; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.Deque; |
| import java.util.Enumeration; |
| import java.util.LinkedList; |
| |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.wiring.BundleRevision; |
| import org.osgi.framework.wiring.BundleWire; |
| import org.osgi.framework.wiring.BundleWiring; |
| |
| /** |
| * This is a simple temporary ClassLoader that delegates to the Bundle, |
| * but does not call loadClass. It is used by the PersistenceUnitInfo |
| */ |
| public class TempBundleDelegatingClassLoader extends ClassLoader { |
| |
| private static final boolean CONTEXT_TRACKING_ENABLED; |
| |
| static { |
| boolean enabled = true; |
| try { |
| Class.forName("org.osgi.framework.wiring.BundleWiring"); |
| } catch (ClassNotFoundException cnfe) { |
| enabled = false; |
| } |
| CONTEXT_TRACKING_ENABLED = enabled; |
| } |
| |
| private final Bundle bundle; |
| |
| private final ThreadLocal<Deque<Bundle>> currentLoadingBundle = new ThreadLocal<Deque<Bundle>>(){ |
| @Override |
| protected Deque<Bundle> initialValue() { |
| return new LinkedList<Bundle>(); |
| } |
| }; |
| |
| public TempBundleDelegatingClassLoader(Bundle b, ClassLoader parent) { |
| super(parent); |
| bundle = b; |
| } |
| |
| @Override |
| protected Class<?> findClass(String className) throws ClassNotFoundException { |
| String classResName = className.replace('.', '/').concat(".class"); |
| |
| //Don't use loadClass, just load the bytes and call defineClass |
| Bundle currentContext = currentLoadingBundle.get().peek(); |
| InputStream is; |
| if(currentContext == null) { |
| is = getResourceAsStream(classResName); |
| } else { |
| is = getResourceInBundleAsStream(classResName, currentContext); |
| } |
| |
| if(is == null) |
| throw new ClassNotFoundException(className); |
| |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| |
| byte[] buff = new byte[4096]; |
| try { |
| try { |
| int read = is.read(buff); |
| while(read >0) { |
| baos.write(buff, 0, read); |
| read = is.read(buff); |
| } |
| }finally { |
| is.close(); |
| } |
| } catch (IOException ioe) { |
| throw new ClassNotFoundException(className, ioe); |
| } |
| |
| buff = baos.toByteArray(); |
| |
| if(CONTEXT_TRACKING_ENABLED) { |
| updateContext(currentContext, className); |
| } |
| try { |
| return defineClass(className, buff, 0, buff.length); |
| } finally { |
| if(CONTEXT_TRACKING_ENABLED) { |
| currentLoadingBundle.get().pop(); |
| } |
| } |
| } |
| |
| private void updateContext(Bundle currentContext, String className) { |
| if(currentContext == null) { |
| currentContext = bundle; |
| } |
| |
| int idx = className.lastIndexOf('.'); |
| String packageName = (idx == -1) ? "" : className.substring(0, idx); |
| |
| Bundle contextToSet = currentContext; |
| |
| BundleWiring wiring = currentContext.adapt(BundleWiring.class); |
| for(BundleWire wire : wiring.getRequiredWires(BundleRevision.PACKAGE_NAMESPACE)) { |
| if(wire.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(packageName)) { |
| contextToSet = wire.getProviderWiring().getBundle(); |
| break; |
| } |
| } |
| currentLoadingBundle.get().push(contextToSet); |
| } |
| |
| @Override |
| protected URL findResource(final String resName) |
| { |
| return findResourceInBundle(resName, bundle); |
| } |
| |
| protected URL findResourceInBundle(final String resName, final Bundle inBundle) |
| { |
| //Bundle.getResource requires privileges that the client may not have but we need |
| //use a doPriv so that only this bundle needs the privileges |
| return AccessController.doPrivileged(new PrivilegedAction<URL>() { |
| |
| public URL run() |
| { |
| return inBundle.getResource(resName); |
| } |
| }); |
| } |
| |
| private InputStream getResourceInBundleAsStream(final String resName, final Bundle inBundle) { |
| URL url = findResourceInBundle(resName, inBundle); |
| try { |
| return (url == null) ? null : url.openStream(); |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| @Override |
| protected Enumeration<URL> findResources(final String resName) throws IOException |
| { |
| return findResourcesInBundle(resName, bundle); |
| } |
| |
| protected Enumeration<URL> findResourcesInBundle(final String resName, final Bundle inBundle) throws IOException |
| { |
| Enumeration<URL> resources = null; |
| try { |
| //Bundle.getResources requires privileges that the client may not have but we need |
| //use a doPriv so that only this bundle needs the privileges |
| resources = AccessController.doPrivileged(new PrivilegedExceptionAction<Enumeration<URL>>() { |
| |
| public Enumeration<URL> run() throws IOException |
| { |
| return inBundle.getResources(resName); |
| } |
| }); |
| } catch(PrivilegedActionException pae) { |
| //thrownException can never be a RuntimeException, as that would escape |
| //the doPriv normally |
| Exception thrownException = pae.getException(); |
| if (thrownException instanceof IOException) { |
| throw (IOException)thrownException; |
| } else { |
| // This code should never get called, but we don't |
| // want to gobble the exception if we see it. |
| throw new UndeclaredThrowableException(thrownException); |
| } |
| } |
| return resources; |
| } |
| } |