blob: 8afe6cb1fedb35d848fb0ccd0645fdc2a55904b8 [file] [log] [blame]
/*
* 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.proxy.impl.interfaces;
import java.security.AllPermission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.aries.proxy.InvocationListener;
import org.apache.aries.proxy.UnableToProxyException;
import org.apache.aries.proxy.impl.common.AbstractWovenProxyAdapter;
import org.apache.aries.proxy.weaving.WovenProxy;
import org.apache.aries.util.AriesFrameworkUtil;
import org.osgi.framework.Bundle;
/** An implementation of ClassLoader that will be used to define our proxy class */
final class ProxyClassLoader extends ClassLoader {
private static final ProtectionDomain PROXY_PROTECTION_DOMAIN;
static {
PermissionCollection pc = new Permissions();
pc.add(new AllPermission());
PROXY_PROTECTION_DOMAIN = new ProtectionDomain(null, pc);
}
/** A {@link Map} of classes we already know */
private final ConcurrentMap<LinkedHashSet<Class<?>>, String> classes =
new ConcurrentHashMap<LinkedHashSet<Class<?>>, String>();
private final ConcurrentMap<String, Class<?>> locatedClasses =
new ConcurrentHashMap<String, Class<?>>();
private final Set<Class<?>> ifaces = new HashSet<Class<?>>();
private final ReadWriteLock ifacesLock = new ReentrantReadWriteLock();
public ProxyClassLoader(Bundle bundle) {
super(AriesFrameworkUtil.getClassLoader(bundle));
}
@Override
protected Class<?> findClass(String className) {
if(WovenProxy.class.getName().equals(className))
return WovenProxy.class;
else if (InvocationListener.class.getName().equals(className))
return InvocationListener.class;
else {
Class<?> c = locatedClasses.get(className);
if(c != null)
return c;
Lock rLock = ifacesLock.readLock();
rLock.lock();
try {
Set<ClassLoader> cls = new HashSet<ClassLoader>();
for(Class<?> iface : ifaces) {
if(cls.add(iface.getClassLoader())) {
try {
c = Class.forName(className, false, iface.getClassLoader());
locatedClasses.put(className, c);
return c;
} catch (ClassNotFoundException e) {
// This is a no-op
}
}
}
} finally {
rLock.unlock();
}
}
return null;
}
/**
* Test whether the classloader is invalidated by the set of classes
* @return
*/
public boolean isInvalid(Set<Class<?>> createSet) {
for (Class<?> iface : createSet) {
try {
Class<?> newIFace = Class.forName(iface.getName(), false, this);
if (!!!newIFace.equals(iface)) return true;
} catch (ClassNotFoundException cnfe) {
return true;
}
}
return false;
}
public Class<?> createProxyClass(Class<?> superclass, SortedSet<Class<?>> interfaces) throws UnableToProxyException {
LinkedHashSet<Class<?>> createSet = new LinkedHashSet<Class<?>>(interfaces);
//Even a null superclass helps with key uniqueness
createSet.add(superclass);
String className = classes.get(createSet);
if(className != null) {
try {
return Class.forName(className, false, this);
} catch (ClassNotFoundException cnfe) {
//This is odd, but we should be able to recreate the class, continue
classes.remove(createSet);
}
}
Lock wLock = ifacesLock.writeLock();
wLock.lock();
try {
//We want the superclass, but only if it isn't null
ifaces.addAll(interfaces);
if(superclass != null) ifaces.add(superclass);
} finally {
wLock.unlock();
}
className = "Proxy" + AbstractWovenProxyAdapter.getSanitizedUUIDString();
InterfaceCombiningClassAdapter icca = new InterfaceCombiningClassAdapter(
className, this, superclass, interfaces);
//Use a special protection domain that grants AllPermission to our Proxy
//object. This is important so that we never get in the way of any security
//checks. This isn't unsafe because we only add simple dispatch/listener code
try {
byte[] bytes = icca.generateBytes();
Class<?> c = defineClass(className, bytes, 0, bytes.length,
PROXY_PROTECTION_DOMAIN);
String old = classes.putIfAbsent(createSet, className);
if(old != null) {
c = Class.forName(className, false, this);
}
return c;
} catch (ClassFormatError cfe) {
throw new UnableToProxyException(createSet.iterator().next(), cfe);
} catch (ClassNotFoundException e) {
throw new UnableToProxyException(createSet.iterator().next(), e);
}
}
}