Skip to content

Commit

Permalink
Merge pull request #1 from muryoh/ipojo-1.12.1-ullink
Browse files Browse the repository at this point in the history
Ipojo 1.12.1-ullink1
  • Loading branch information
muryoh authored Sep 21, 2016
2 parents 3d048c8 + 0f71c43 commit d79f53d
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 18 deletions.
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<packaging>bundle</packaging>
<name>Apache Felix iPOJO</name>
<artifactId>org.apache.felix.ipojo</artifactId>
<version>1.12.1</version>
<version>1.12.1-ullink1</version>

<properties>
<!--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,19 +416,19 @@ private RuntimeException createExceptionToThrow() {
return new RuntimeException(message);
}

private Object createNullableObject() {
private void createNullableObject() {
// To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
// access to the service specification.
if ( ! getSpecification().isInterface()) {
getHandler().getLogger().log(Log.INFO, "Cannot create the nullable object for " + getSpecification()
.getName() + " - the specification is not an interface");
return null;
return;
}

try {
ClassLoader cl = new NullableClassLoader(
getHandler().getInstanceManager().getClazz().getClassLoader(),
getSpecification().getClassLoader());
findClassLoadersFromSpecification(getSpecification()));

m_nullable =
Proxy.newProxyInstance(cl, new Class[]{
Expand All @@ -441,8 +441,28 @@ private Object createNullableObject() {
} catch (Throwable e) { // Catch any other exception that can occurs
throw new IllegalStateException("Cannot create the Nullable object, an unexpected error occurs", e);
}
}

return m_nullable;
private List<ClassLoader> findClassLoadersFromSpecification(Class clazz) {
ArrayList<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
ClassLoader specificationCL = clazz.getClassLoader();
classLoaders.add(specificationCL);
// use Class.getMethods() to go thru the full hierarchy of classes of the specification
for (Method method : clazz.getMethods()) {
for (Class<?> parameterType : method.getParameterTypes()) {
ClassLoader parameterCL = parameterType.getClassLoader();
if (parameterCL != null && !classLoaders.contains(parameterCL)) {
classLoaders.add(parameterCL);
}
}
if (!Void.TYPE.equals(method.getReturnType())) {
ClassLoader returnCL = method.getReturnType().getClassLoader();
if (returnCL != null && !classLoaders.contains(returnCL)) {
classLoaders.add(returnCL);
}
}
}
return classLoaders;
}

/**
Expand Down Expand Up @@ -1038,42 +1058,49 @@ private static class NullableClassLoader extends ClassLoader {
/**
* Component classloader.
*/
private ClassLoader m_component;
private ClassLoader m_component;
/**
* Specification classloader.
* Specification classloaders.
*/
private ClassLoader m_specification;
private List<ClassLoader> m_classLoadersFromSpecification;

/**
* Creates a NullableClassLoader.
*
* @param cmp the component class loader.
* @param spec the specification class loader.
* @param cmp the component class loader.
* @param classLoadersFromSpecification the specification class loader plus the ones referenced by parameters and return types.
*/
public NullableClassLoader(ClassLoader cmp, ClassLoader spec) {
public NullableClassLoader(ClassLoader cmp, List<ClassLoader> classLoadersFromSpecification) {
m_component = cmp;
m_specification = spec;
m_classLoadersFromSpecification = classLoadersFromSpecification;
}

/**
* Loads the given class.
* This method uses the classloader of the component class
* and (if not found) the specification classloader.
* and (if not found) the specification classloaders.
* Throws the last {@link ClassNotFoundException} caught while trying
* to load the class from the specifiation classloaders
*
* @param name the class name
* @return the class object
* @throws ClassNotFoundException if the class is not found by the two classloaders.
* @throws ClassNotFoundException if the class is not found by the classloaders.
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
public Class loadClass(String name) throws ClassNotFoundException {
try {
return m_component.loadClass(name);
} catch (ClassNotFoundException e) {
return m_specification.loadClass(name);
ClassNotFoundException lastCaught = null;
for (ClassLoader classLoader : m_classLoadersFromSpecification) {
try {
return classLoader.loadClass(name);
} catch (ClassNotFoundException cnfe) {
lastCaught = cnfe;
}
}
throw lastCaught;
}
}


}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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.felix.ipojo.handlers.dependency;

import java.lang.reflect.Proxy;
import org.apache.felix.ipojo.InstanceManager;
import org.apache.felix.ipojo.Nullable;
import org.apache.felix.ipojo.handlers.providedservice.ComponentTestWithSuperClass;
import org.apache.felix.ipojo.test.MockBundle;
import org.mockito.Mockito;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import junit.framework.Assert;
import junit.framework.TestCase;

public class NullableTest extends TestCase {

public void testOnGet_whenNullableEnabled_returnsAnInstanceOfNullableAndSpecification() {
Bundle bundle = new MockBundle(Dependency.class.getClassLoader());
BundleContext context = Mockito.mock(BundleContext.class);
InstanceManager im = Mockito.mock(InstanceManager.class);
Mockito.when(im.getClazz()).thenReturn(ComponentTestWithSuperClass.class);
DependencyHandler handler = Mockito.mock(DependencyHandler.class);
Mockito.when(handler.getInstanceManager()).thenReturn(im);
Dependency dependency = new Dependency(handler, "a_field", TestSpecification.class, null, true, false, true,
false, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
dependency.start();

Object service = dependency.onGet(null, null, null);

Assert.assertTrue(service instanceof Nullable);
Assert.assertTrue(service instanceof TestSpecification);
}

public void testOnGet_whenNullableEnabled_returnsAProxyWithNullableObjectAsInvocationHandler() {
Bundle bundle = new MockBundle(Dependency.class.getClassLoader());
BundleContext context = Mockito.mock(BundleContext.class);
InstanceManager im = Mockito.mock(InstanceManager.class);
Mockito.when(im.getClazz()).thenReturn(ComponentTestWithSuperClass.class);
DependencyHandler handler = Mockito.mock(DependencyHandler.class);
Mockito.when(handler.getInstanceManager()).thenReturn(im);
Dependency dependency = new Dependency(handler, "a_field", TestSpecification.class, null, true, false, true,
false, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
dependency.start();

Object service = dependency.onGet(null, null, null);

Assert.assertTrue(service instanceof Proxy);
Assert.assertTrue(Proxy.getInvocationHandler(service) instanceof NullableObject);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.felix.ipojo.handlers.dependency;

public interface TestSpecification
{
public String doSomething(String param);
}

0 comments on commit d79f53d

Please sign in to comment.