/* * 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.dm.itest.api; import org.apache.felix.dm.Component; import org.apache.felix.dm.DependencyManager; import org.apache.felix.dm.itest.util.Ensure; import org.apache.felix.dm.itest.util.TestBase; /** * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class AspectDynamicsTest extends TestBase { public void testDynamicallyAddAndRemoveAspect() { DependencyManager m = getDM(); // helper class that ensures certain steps get executed in sequence Ensure e = new Ensure(); Ensure aspectStopEnsure = new Ensure(); // create a service provider and consumer Component provider = m.createComponent().setImplementation(new ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null); Component provider2 = m.createComponent().setImplementation(new ServiceProvider2(e)).setInterface(ServiceInterface2.class.getName(), null); Component consumer = m.createComponent().setImplementation(new ServiceConsumer(e)) .add(m.createServiceDependency().setService(ServiceInterface.class).setRequired(true).setCallbacks("add", null, null, "swap")); Component aspect = m.createAspectService(ServiceInterface.class, null, 1, null).setImplementation(new ServiceAspect(e, aspectStopEnsure)); m.add(consumer); m.add(provider); // the consumer should invoke the provider here, and when done, arrive at step 3 // finally wait for step 6 before continuing e.waitForStep(3, 15000); m.add(aspect); // after adding the aspect, we wait for its init to be invoked, arriving at // step 4 after an instance bound dependency was added (on a service provided by // provider 2) e.waitForStep(4, 15000); m.add(provider2); // after adding provider 2, we should now see the client being swapped, so // we wait for step 5 to happen e.waitForStep(5, 15000); // now we continue with step 6, which will trigger the next part of the consumer's // run method to be executed e.step(6); // invoking step 7, 8 and 9 when invoking the aspect which in turn invokes the // dependency and the original service, so we wait for that to finish here, which // is after step 10 has been reached (the client will now wait for step 12) e.waitForStep(10, 15000); m.remove(aspect); aspectStopEnsure.waitForStep(1, 15000); // removing the aspect should trigger step 11 (in the swap method of the consumer) e.waitForStep(11, 15000); // step 12 triggers the client to continue e.step(12); // wait for step 13, the final invocation of the provided service (without aspect) e.waitForStep(13, 15000); // clean up m.remove(provider2); m.remove(provider); m.remove(consumer); e.waitForStep(16, 15000); m.clear(); } static interface ServiceInterface { public void invoke(Runnable run); } static interface ServiceInterface2 { public void invoke(); } static class ServiceProvider2 implements ServiceInterface2 { private final Ensure m_ensure; public ServiceProvider2(Ensure ensure) { m_ensure = ensure; } public void invoke() { m_ensure.step(9); } public void stop() { m_ensure.step(); } } static class ServiceProvider implements ServiceInterface { private final Ensure m_ensure; public ServiceProvider(Ensure e) { m_ensure = e; } public void invoke(Runnable run) { run.run(); } public void stop() { m_ensure.step(); } } static class ServiceAspect implements ServiceInterface { private final Ensure m_ensure; private volatile ServiceInterface m_originalService; private volatile ServiceInterface2 m_injectedService; private volatile Component m_service; private volatile DependencyManager m_manager; private final Ensure m_stopEnsure; public ServiceAspect(Ensure e, Ensure stopEnsure) { m_ensure = e; m_stopEnsure = stopEnsure; } public void init() { m_service.add(m_manager.createServiceDependency() .setService(ServiceInterface2.class) .setRequired(true) ); m_ensure.step(4); } public void invoke(Runnable run) { m_ensure.step(7); m_originalService.invoke(run); m_injectedService.invoke(); } public void stop() { m_stopEnsure.step(1); } } static class ServiceConsumer implements Runnable { private volatile ServiceInterface m_service; private final Ensure m_ensure; private final Ensure.Steps m_swapSteps = new Ensure.Steps(5, 11); public ServiceConsumer(Ensure e) { m_ensure = e; } void add(ServiceInterface service) { m_service = service; } void swap(ServiceInterface oldService, ServiceInterface newService) { System.out.println("swap: old=" + oldService + ", new=" + newService); m_ensure.steps(m_swapSteps); m_service = newService; } public void init() { Thread t = new Thread(this); t.start(); } public void run() { m_ensure.step(1); m_service.invoke(Ensure.createRunnableStep(m_ensure, 2)); m_ensure.step(3); m_ensure.waitForStep(6, 15000); m_service.invoke(Ensure.createRunnableStep(m_ensure, 8)); m_ensure.step(10); m_ensure.waitForStep(12, 15000); m_service.invoke(Ensure.createRunnableStep(m_ensure, 13)); } public void stop() { m_ensure.step(); } } }