content: /*
   * 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.blueprint.itests;
  
  import static org.apache.aries.blueprint.itests.Helper.mvnBundle;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertTrue;
  import static org.junit.Assert.fail;
  
  import java.util.Hashtable;
  import java.util.List;
  import java.util.concurrent.atomic.AtomicBoolean;
  
  import org.apache.aries.blueprint.sample.BindingListener;
  import org.apache.aries.blueprint.sample.DefaultRunnable;
  import org.apache.aries.blueprint.sample.DestroyTest;
  import org.apache.aries.blueprint.sample.InterfaceA;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.ops4j.pax.exam.Configuration;
  import org.ops4j.pax.exam.CoreOptions;
  import org.ops4j.pax.exam.Option;
  import org.ops4j.pax.exam.junit.PaxExam;
  import org.osgi.framework.Bundle;
  import org.osgi.framework.Constants;
  import org.osgi.framework.ServiceRegistration;
  import org.osgi.service.blueprint.container.BlueprintContainer;
  import org.osgi.service.blueprint.container.ServiceUnavailableException;
  
  @RunWith(PaxExam.class)
  public class TestReferences extends AbstractBlueprintIntegrationTest {
  
      @SuppressWarnings("rawtypes")
      @Test
      public void testUnaryReference() throws Exception {
          BlueprintContainer blueprintContainer = Helper.getBlueprintContainerForBundle(context(), "org.apache.aries.blueprint.sample");
          assertNotNull(blueprintContainer);
  
          BindingListener listener = (BindingListener) blueprintContainer.getComponentInstance("bindingListener");
          assertNull(listener.getA());
          assertNull(listener.getReference());
  
          InterfaceA a = (InterfaceA) blueprintContainer.getComponentInstance("ref2");
          try {
              a.hello("world");
              fail("A ServiceUnavailableException should have been thrown");
          } catch (ServiceUnavailableException e) {
              // Ignore, expected
          }
  
          ServiceRegistration reg1 = bundleContext.registerService(InterfaceA.class.getName(), new InterfaceA() {
              public String hello(String msg) {
                  return "Hello " + msg + "!";
              }
          }, null);
          waitForAsynchronousHandling();
  
          assertNotNull(listener.getA());
          assertNotNull(listener.getReference());
          assertEquals("Hello world!", a.hello("world"));
  
          Hashtable<String, Object> props = new Hashtable<String, Object>();
          props.put(Constants.SERVICE_RANKING, Integer.valueOf(1));
          ServiceRegistration reg2 = bundleContext.registerService(InterfaceA.class.getName(), new InterfaceA() {
              public String hello(String msg) {
                  return "Good morning " + msg + "!";
              }
          }, props);
  
          waitForAsynchronousHandling();
  
          assertNotNull(listener.getA());
          assertNotNull(listener.getReference());
          assertEquals("Hello world!", a.hello("world"));
  
          reg1.unregister();
          waitForAsynchronousHandling();
          assertNotNull(listener.getA());
          assertNotNull(listener.getReference());
          assertEquals("Good morning world!", a.hello("world"));
  
          reg2.unregister();
          waitForAsynchronousHandling();
  
          assertNull(listener.getA());
          assertNull(listener.getReference());
          try {
              a.hello("world");
              fail("A ServiceUnavailableException should have been thrown");
          } catch (ServiceUnavailableException e) {
              // Ignore, expected
          }
      }
  
      @Test
      public void testListReferences() throws Exception {
          BlueprintContainer blueprintContainer = Helper.getBlueprintContainerForBundle(context(), "org.apache.aries.blueprint.sample");
          assertNotNull(blueprintContainer);
  
          BindingListener listener = (BindingListener) blueprintContainer.getComponentInstance("listBindingListener");
          assertNull(listener.getA());
          assertNull(listener.getReference());
  
          List<?> refs = (List<?>) blueprintContainer.getComponentInstance("ref-list");
          assertNotNull(refs);
          assertTrue(refs.isEmpty());
  
          InterfaceA testService = new InterfaceA() {
              public String hello(String msg) {
                  return "Hello " + msg + "!";
              }
          };
          bundleContext.registerService(InterfaceA.class.getName(), testService, null);
      
          waitForAsynchronousHandling();
          assertNotNull(listener.getA());
          assertNotNull(listener.getReference());
          assertEquals(1, refs.size());
          InterfaceA a = (InterfaceA) refs.get(0);
          assertNotNull(a);
          assertEquals("Hello world!", a.hello("world"));
  
      }
      
      @SuppressWarnings("rawtypes")
      @Test
      public void testDefaultReference() throws Exception {
        BlueprintContainer blueprintContainer = Helper.getBlueprintContainerForBundle(context(), "org.apache.aries.blueprint.sample");
        assertNotNull(blueprintContainer);
  
        Runnable refRunnable = (Runnable) blueprintContainer.getComponentInstance("refWithDefault");
        DefaultRunnable defaultRunnable = (DefaultRunnable) blueprintContainer.getComponentInstance("defaultRunnable");
        refRunnable.run();
        waitForAsynchronousHandling();
        Thread.sleep(2000);
        
        assertEquals("The default runnable was not called", 1, defaultRunnable.getCount());
        
        final AtomicBoolean called = new AtomicBoolean(false);
        Runnable mockService = new Runnable() {
          public void run() {
              called.set(true);
          }
        };
        
        ServiceRegistration reg = bundleContext.registerService(Runnable.class.getName(), mockService, null);
        waitForAsynchronousHandling();
        Thread.sleep(2000);
  
        refRunnable.run();
        
        assertEquals("The default runnable was called when a service was bound", 1, defaultRunnable.getCount());
        
        assertTrue("Service should have been called", called.get());
        
        reg.unregister();
        waitForAsynchronousHandling();
        Thread.sleep(2000);
  
        refRunnable.run();
        
        assertEquals("The default runnable was not called", 2, defaultRunnable.getCount());
      }
      
      @Test
      public void testReferencesCallableInDestroy() throws Exception {
        bundleContext.registerService(Runnable.class.getName(), new Thread(), null);
        
        BlueprintContainer blueprintContainer = Helper.getBlueprintContainerForBundle(context(), "org.apache.aries.blueprint.sample");
        assertNotNull(blueprintContainer);
        
        DestroyTest dt = (DestroyTest) blueprintContainer.getComponentInstance("destroyCallingReference");
        
        Bundle b = findBundle("org.apache.aries.blueprint.sample");
        assertNotNull(b);
        b.stop();
        
        assertTrue("The destroy method was called", dt.waitForDestruction(1000));
        
        Exception e = dt.getDestroyFailure();
        
        if (e != null) throw e;
      }
  
      private Bundle findBundle(String bsn)
      {
        for (Bundle b : bundleContext.getBundles()) {
          if (bsn.equals(b.getSymbolicName())) return b;
        }
        
        return null;
      }
  
      private void waitForAsynchronousHandling() throws InterruptedException {
        // Since service events are handled asynchronously in AbstractServiceReferenceRecipe, pause
         Thread.sleep(200);
        
     }
  
     @Configuration
      public static Option[] configuration() {
          return new Option[] {
                  CoreOptions.junitBundles(),
                  Helper.blueprintBundles(),
                  mvnBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint.sample")
          };
      }
  
  }
  