/* | |
* 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.proxy.impl.common; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.HashSet; | |
import java.util.Set; | |
import org.apache.aries.proxy.UnableToProxyException; | |
import org.apache.aries.proxy.impl.NLS; | |
import org.objectweb.asm.ClassReader; | |
import org.objectweb.asm.ClassWriter; | |
/** | |
* We need to override ASM's default behaviour in {@link #getCommonSuperClass(String, String)} | |
* so that it doesn't load classes (which it was doing on the wrong {@link ClassLoader} | |
* anyway...) | |
*/ | |
public final class OSGiFriendlyClassWriter extends ClassWriter { | |
private static final String OBJECT_INTERNAL_NAME = "java/lang/Object"; | |
private final ClassLoader loader; | |
public OSGiFriendlyClassWriter(ClassReader arg0, int arg1, ClassLoader loader) { | |
super(arg0, arg1); | |
this.loader = loader; | |
} | |
public OSGiFriendlyClassWriter(int arg0, ClassLoader loader) { | |
super(arg0); | |
this.loader = loader; | |
} | |
/** | |
* We provide an implementation that doesn't cause class loads to occur. It may | |
* not be sufficient because it expects to find the common parent using a single | |
* classloader, though in fact the common parent may only be loadable by another | |
* bundle from which an intermediate class is loaded | |
* | |
* precondition: arg0 and arg1 are not equal. (checked before this method is called) | |
*/ | |
@Override | |
protected final String getCommonSuperClass(String arg0, String arg1) { | |
//If either is Object, then Object must be the answer | |
if(arg0.equals(OBJECT_INTERNAL_NAME) || arg1.equals(OBJECT_INTERNAL_NAME)) { | |
return OBJECT_INTERNAL_NAME; | |
} | |
Set<String> names = new HashSet<String>(); | |
names.add(arg0); | |
names.add(arg1); | |
//Try loading the class (in ASM not for real) | |
try { | |
boolean bRunning = true; | |
boolean aRunning = true; | |
InputStream is; | |
String arg00 = arg0; | |
String arg11 = arg1; | |
String unable = null; | |
while(aRunning || bRunning ) { | |
if(aRunning) { | |
is = loader.getResourceAsStream(arg00 + ".class"); | |
if(is != null) { | |
ClassReader cr = new ClassReader(is); | |
arg00 = cr.getSuperName(); | |
if(arg00 == null) { | |
if (names.size() == 2) { | |
return OBJECT_INTERNAL_NAME; //arg0 is an interface | |
} | |
aRunning = false; //old arg00 was java.lang.Object | |
} else if(!!!names.add(arg00)) { | |
return arg00; | |
} | |
} else { | |
//The class file isn't visible on this ClassLoader | |
unable = arg0; | |
aRunning = false; | |
} | |
} | |
if(bRunning) { | |
is = loader.getResourceAsStream(arg11 + ".class"); | |
if(is != null) { | |
ClassReader cr = new ClassReader(is); | |
arg11 = cr.getSuperName(); | |
if(arg11 == null) { | |
if (names.size() == 3) { | |
return OBJECT_INTERNAL_NAME; //arg1 is an interface | |
} | |
bRunning = false; //old arg11 was java.lang.Object | |
} else if(!!!names.add(arg11)) { | |
return arg11; | |
} | |
} else { | |
unable = arg1; | |
bRunning = false; | |
} | |
} | |
} | |
if (unable == null) { | |
throw new RuntimeException(NLS.MESSAGES.getMessage("no.common.superclass", arg0, arg1)); | |
} else { | |
throw new RuntimeException(new UnableToProxyException(unable, NLS.MESSAGES.getMessage("no.common.superclass", arg0, arg1))); | |
} | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} |