blob: af7052fbe795e64cc30602274d5063bba80fed7d [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 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.cxf.dosgi.dsw.service;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.apache.cxf.dosgi.dsw.api.DistributionProvider;
import org.apache.cxf.dosgi.dsw.api.Endpoint;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.easymock.IMocksControl;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.remoteserviceadmin.EndpointDescription;
import org.osgi.service.remoteserviceadmin.ExportRegistration;
import org.osgi.service.remoteserviceadmin.ImportRegistration;
import org.osgi.service.remoteserviceadmin.RemoteConstants;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.isA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@SuppressWarnings({
"rawtypes", "unchecked"
})
public class RemoteServiceAdminCoreTest {
private static final String MYCONFIG = "myconfig";
@Test
public void testDontExportOwnServiceProxies() throws InvalidSyntaxException {
IMocksControl c = EasyMock.createControl();
Bundle b = c.createMock(Bundle.class);
BundleContext bc = c.createMock(BundleContext.class);
EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
bc.addServiceListener(EasyMock.<ServiceListener>anyObject(), EasyMock.<String>anyObject());
EasyMock.expectLastCall().anyTimes();
bc.removeServiceListener(EasyMock.<ServiceListener>anyObject());
EasyMock.expectLastCall().anyTimes();
Dictionary<String, String> d = new Hashtable<String, String>();
EasyMock.expect(b.getHeaders()).andReturn(d).anyTimes();
ServiceReference sref = c.createMock(ServiceReference.class);
EasyMock.expect(sref.getBundle()).andReturn(b).anyTimes();
EasyMock.expect(sref.getPropertyKeys())
.andReturn(new String[]{"objectClass", "service.exported.interfaces"}).anyTimes();
EasyMock.expect(sref.getProperty("objectClass")).andReturn(new String[] {"a.b.C"}).anyTimes();
EasyMock.expect(sref.getProperty(RemoteConstants.SERVICE_IMPORTED)).andReturn(true).anyTimes();
EasyMock.expect(sref.getProperty("service.exported.interfaces")).andReturn("*").anyTimes();
DistributionProvider provider = c.createMock(DistributionProvider.class);
c.replay();
RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, bc, provider);
// must return an empty List as sref if from the same bundle
List<ExportRegistration> exRefs = rsaCore.exportService(sref, null);
assertNotNull(exRefs);
assertEquals(0, exRefs.size());
// must be empty
assertEquals(rsaCore.getExportedServices().size(), 0);
c.verify();
}
@Test
public void testImport() {
IMocksControl c = EasyMock.createNiceControl();
Bundle b = c.createMock(Bundle.class);
BundleContext bc = c.createMock(BundleContext.class);
Dictionary<String, String> d = new Hashtable<String, String>();
EasyMock.expect(b.getHeaders()).andReturn(d).anyTimes();
EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
EasyMock.expect(b.getSymbolicName()).andReturn("BundleName").anyTimes();
EndpointDescription endpoint = creatEndpointDesc("unsupportedConfiguration");
DistributionProvider provider = c.createMock(DistributionProvider.class);
EasyMock.expect(provider.getSupportedTypes())
.andReturn(new String[]{MYCONFIG}).atLeastOnce();
c.replay();
RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, bc, provider);
// must be null as the endpoint doesn't contain any usable configurations
assertNull(rsaCore.importService(endpoint));
// must be empty
assertEquals(0, rsaCore.getImportedEndpoints().size());
EndpointDescription endpoint2 = creatEndpointDesc(MYCONFIG);
ImportRegistration ireg = rsaCore.importService(endpoint2);
assertNotNull(ireg);
assertEquals(1, rsaCore.getImportedEndpoints().size());
// lets import the same endpoint once more -> should get a copy of the ImportRegistration
ImportRegistration ireg2 = rsaCore.importService(endpoint2);
assertNotNull(ireg2);
assertEquals(2, rsaCore.getImportedEndpoints().size());
assertEquals(ireg.getImportReference(), (rsaCore.getImportedEndpoints().toArray())[0]);
assertEquals(ireg.getImportReference().getImportedEndpoint(), ireg2.getImportReference()
.getImportedEndpoint());
// remove the registration
// first call shouldn't remove the import
ireg2.close();
assertEquals(1, rsaCore.getImportedEndpoints().size());
// second call should really close and remove the import
ireg.close();
assertEquals(0, rsaCore.getImportedEndpoints().size());
c.verify();
}
private EndpointDescription creatEndpointDesc(String configType) {
Map<String, Object> p = new HashMap<String, Object>();
p.put(RemoteConstants.ENDPOINT_ID, "http://google.de");
p.put(Constants.OBJECTCLASS, new String[] {
"es.schaaf.my.class"
});
p.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, configType);
EndpointDescription endpoint = new EndpointDescription(p);
return endpoint;
}
@Test
public void testExport() throws Exception {
BundleContext bc = EasyMock.createMock(BundleContext.class);
EasyMock.expect(bc.getProperty(Constants.FRAMEWORK_VERSION)).andReturn(null).anyTimes();
bc.addServiceListener(EasyMock.<ServiceListener>anyObject(), EasyMock.<String>anyObject());
EasyMock.expectLastCall().anyTimes();
bc.removeServiceListener(EasyMock.<ServiceListener>anyObject());
EasyMock.expectLastCall().anyTimes();
EasyMock.expect(bc.getServiceReferences(EasyMock.<String>anyObject(),
EasyMock.<String>anyObject())).andReturn(null).anyTimes();
EasyMock.expect(bc.getAllServiceReferences(EasyMock.<String>anyObject(),
EasyMock.<String>anyObject())).andReturn(null).anyTimes();
Bundle b = createDummyRsaBundle(bc);
final Map<String, Object> sProps = new HashMap<String, Object>();
sProps.put("objectClass", new String[] {"java.lang.Runnable"});
sProps.put("service.id", 51L);
sProps.put("myProp", "myVal");
sProps.put("service.exported.interfaces", "*");
ServiceReference sref = mockServiceReference(sProps);
Runnable svcObject = EasyMock.createNiceMock(Runnable.class);
EasyMock.replay(svcObject);
EasyMock.expect(bc.getService(sref)).andReturn(svcObject).anyTimes();
EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
EasyMock.expect(bc.createFilter("(service.id=51)"))
.andReturn(FrameworkUtil.createFilter("(service.id=51)")).anyTimes();
EasyMock.replay(bc);
Map<String, Object> eProps = new HashMap<String, Object>(sProps);
eProps.put("endpoint.id", "http://something");
eProps.put("service.imported.configs", new String[] {"org.apache.cxf.ws"});
final EndpointDescription epd = new EndpointDescription(eProps);
Endpoint er = new Endpoint() {
@Override
public void close() throws IOException {
}
@Override
public EndpointDescription description() {
return epd;
}
};
DistributionProvider handler = EasyMock.createMock(DistributionProvider.class);
EasyMock.expect(handler.exportService(anyObject(ServiceReference.class),
anyObject(Map.class), isA(Class[].class))).andReturn(er);
EasyMock.replay(handler);
RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, bc, handler);
// Export the service for the first time
List<ExportRegistration> ereg = rsaCore.exportService(sref, null);
assertEquals(1, ereg.size());
assertNull(ereg.get(0).getException());
assertSame(sref, ereg.get(0).getExportReference().getExportedService());
EndpointDescription endpoint = ereg.get(0).getExportReference().getExportedEndpoint();
Map<String, Object> edProps = endpoint.getProperties();
assertEquals("http://something", edProps.get("endpoint.id"));
assertNotNull(edProps.get("service.imported"));
assertTrue(Arrays.equals(new String[] {"java.lang.Runnable"},
(Object[]) edProps.get("objectClass")));
assertTrue(Arrays.equals(new String[] {"org.apache.cxf.ws"},
(Object[]) edProps.get("service.imported.configs")));
// Ask to export the same service again, this should not go through the whole process again but simply return
// a copy of the first instance.
final Map<String, Object> sProps2 = new HashMap<String, Object>();
sProps2.put("objectClass", new String[] {"java.lang.Runnable"});
sProps2.put("service.id", 51L);
sProps2.put("service.exported.interfaces", "*");
ServiceReference sref2 = mockServiceReference(sProps2);
Map<String, Object> props2 = new HashMap<String, Object>();
props2.put("myProp", "myVal");
List<ExportRegistration> ereg2 = rsaCore.exportService(sref2, props2);
assertEquals(1, ereg2.size());
assertNull(ereg2.get(0).getException());
assertEquals(ereg.get(0).getExportReference().getExportedEndpoint().getProperties(),
ereg2.get(0).getExportReference().getExportedEndpoint().getProperties());
// Look at the exportedServices data structure
Field field = RemoteServiceAdminCore.class.getDeclaredField("exportedServices");
field.setAccessible(true);
Map<Map<String, Object>, Collection<ExportRegistration>> exportedServices =
(Map<Map<String, Object>, Collection<ExportRegistration>>) field.get(rsaCore);
assertEquals("One service was exported", 1, exportedServices.size());
assertEquals("There are 2 export registrations (identical copies)",
2, exportedServices.values().iterator().next().size());
// Unregister one of the exports
rsaCore.removeExportRegistration((ExportRegistrationImpl) ereg.get(0));
assertEquals("One service was exported", 1, exportedServices.size());
assertEquals("There 1 export registrations left",
1, exportedServices.values().iterator().next().size());
// Unregister the other export
rsaCore.removeExportRegistration((ExportRegistrationImpl) ereg2.get(0));
assertEquals("No more exported services", 0, exportedServices.size());
}
private Bundle createDummyRsaBundle(BundleContext bc) {
Bundle b = EasyMock.createNiceMock(Bundle.class);
EasyMock.expect(b.getBundleContext()).andReturn(bc).anyTimes();
EasyMock.expect(b.getSymbolicName()).andReturn("rsabundle").anyTimes();
EasyMock.expect(b.getHeaders()).andReturn(new Hashtable<String, String>()).anyTimes();
EasyMock.replay(b);
return b;
}
@Test
public void testExportException() throws Exception {
BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
Bundle b = createDummyRsaBundle(bc);
final Map<String, Object> sProps = new HashMap<String, Object>();
sProps.put("objectClass", new String[] {"java.lang.Runnable"});
sProps.put("service.id", 51L);
sProps.put("service.exported.interfaces", "*");
ServiceReference sref = mockServiceReference(sProps);
Runnable svcObject = EasyMock.createNiceMock(Runnable.class);
EasyMock.replay(svcObject);
EasyMock.expect(bc.getService(sref)).andReturn(svcObject).anyTimes();
EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
EasyMock.replay(bc);
Map<String, Object> eProps = new HashMap<String, Object>(sProps);
eProps.put("endpoint.id", "http://something");
eProps.put("service.imported.configs", new String[] {"org.apache.cxf.ws"});
DistributionProvider handler = EasyMock.createMock(DistributionProvider.class);
EasyMock.expect(handler.exportService(anyObject(ServiceReference.class),
anyObject(Map.class), isA(Class[].class))).andThrow(new TestException());
EasyMock.replay(handler);
RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, bc, handler);
List<ExportRegistration> ereg = rsaCore.exportService(sref, sProps);
assertEquals(1, ereg.size());
assertTrue(ereg.get(0).getException() instanceof TestException);
// Look at the exportedServices data structure
Field field = RemoteServiceAdminCore.class.getDeclaredField("exportedServices");
field.setAccessible(true);
Map<Map<String, Object>, Collection<ExportRegistration>> exportedServices =
(Map<Map<String, Object>, Collection<ExportRegistration>>) field.get(rsaCore);
assertEquals("One service was exported", 1, exportedServices.size());
assertEquals("There is 1 export registration",
1, exportedServices.values().iterator().next().size());
}
private ServiceReference mockServiceReference(final Map<String, Object> sProps) throws ClassNotFoundException {
BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
Bundle b = EasyMock.createNiceMock(Bundle.class);
EasyMock.expect(b.getBundleContext()).andReturn(bc).anyTimes();
EasyMock.expect((Class)b.loadClass(Runnable.class.getName())).andReturn(Runnable.class);
EasyMock.replay(b);
EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
EasyMock.replay(bc);
ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
EasyMock.expect(sref.getBundle()).andReturn(b).anyTimes();
EasyMock.expect(sref.getPropertyKeys()).andReturn(sProps.keySet().toArray(new String[] {})).anyTimes();
EasyMock.expect(sref.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
@Override
public Object answer() throws Throwable {
return sProps.get(EasyMock.getCurrentArguments()[0]);
}
}).anyTimes();
EasyMock.replay(sref);
return sref;
}
@SuppressWarnings("serial")
private static class TestException extends RuntimeException {
}
@Test
public void testOverlayProperties() {
Map<String, Object> sProps = new HashMap<String, Object>();
Map<String, Object> aProps = new HashMap<String, Object>();
RemoteServiceAdminCore.overlayProperties(sProps, aProps);
assertEquals(0, sProps.size());
sProps.put("aaa", "aval");
sProps.put("bbb", "bval");
sProps.put(Constants.OBJECTCLASS, new String[] {"X"});
sProps.put(Constants.SERVICE_ID, 17L);
aProps.put("AAA", "achanged");
aProps.put("CCC", "CVAL");
aProps.put(Constants.OBJECTCLASS, new String[] {"Y"});
aProps.put(Constants.SERVICE_ID.toUpperCase(), 51L);
Map<String, Object> aPropsOrg = new HashMap<String, Object>(aProps);
RemoteServiceAdminCore.overlayProperties(sProps, aProps);
assertEquals("The additional properties should not be modified", aPropsOrg, aProps);
assertEquals(5, sProps.size());
assertEquals("achanged", sProps.get("aaa"));
assertEquals("bval", sProps.get("bbb"));
assertEquals("CVAL", sProps.get("CCC"));
assertTrue("Should not be possible to override the objectClass property",
Arrays.equals(new String[] {"X"}, (Object[]) sProps.get(Constants.OBJECTCLASS)));
assertEquals("Should not be possible to override the service.id property",
17L, sProps.get(Constants.SERVICE_ID));
}
@Test
public void testOverlayProperties2() {
Map<String, Object> original = new HashMap<String, Object>();
original.put("MyProp", "my value");
original.put(Constants.OBJECTCLASS, "myClass");
Map<String, Object> copy = new HashMap<String, Object>();
copy.putAll(original);
// nothing should change here
Map<String, Object> overload = new HashMap<String, Object>();
RemoteServiceAdminCore.overlayProperties(copy, overload);
assertEquals(original.size(), copy.size());
for (Object key : original.keySet()) {
assertEquals(original.get(key), copy.get(key));
}
copy.clear();
copy.putAll(original);
// a property should be added
overload = new HashMap<String, Object>();
overload.put("new", "prop");
RemoteServiceAdminCore.overlayProperties(copy, overload);
assertEquals(original.size() + 1, copy.size());
for (Object key : original.keySet()) {
assertEquals(original.get(key), copy.get(key));
}
assertNotNull(overload.get("new"));
assertEquals("prop", overload.get("new"));
copy.clear();
copy.putAll(original);
// only one property should be added
overload = new HashMap<String, Object>();
overload.put("new", "prop");
overload.put("NEW", "prop");
RemoteServiceAdminCore.overlayProperties(copy, overload);
assertEquals(original.size() + 1, copy.size());
for (Object key : original.keySet()) {
assertEquals(original.get(key), copy.get(key));
}
assertNotNull(overload.get("new"));
assertEquals("prop", overload.get("new"));
copy.clear();
copy.putAll(original);
// nothing should change here
overload = new HashMap<String, Object>();
overload.put(Constants.OBJECTCLASS, "assd");
overload.put(Constants.SERVICE_ID, "asasdasd");
RemoteServiceAdminCore.overlayProperties(copy, overload);
assertEquals(original.size(), copy.size());
for (Object key : original.keySet()) {
assertEquals(original.get(key), copy.get(key));
}
copy.clear();
copy.putAll(original);
// overwrite own prop
overload = new HashMap<String, Object>();
overload.put("MyProp", "newValue");
RemoteServiceAdminCore.overlayProperties(copy, overload);
assertEquals(original.size(), copy.size());
for (Object key : original.keySet()) {
if (!"MyProp".equals(key)) {
assertEquals(original.get(key), copy.get(key));
}
}
assertEquals("newValue", copy.get("MyProp"));
copy.clear();
copy.putAll(original);
// overwrite own prop in different case
overload = new HashMap<String, Object>();
overload.put("MYPROP", "newValue");
RemoteServiceAdminCore.overlayProperties(copy, overload);
assertEquals(original.size(), copy.size());
for (Object key : original.keySet()) {
if (!"MyProp".equals(key)) {
assertEquals(original.get(key), copy.get(key));
}
}
assertEquals("newValue", copy.get("MyProp"));
}
}