Beispiel #1
0
  /**
   * Called when this bundle is started so the Framework can perform the bundle-specific activities
   * necessary to start this bundle. This method can be used to register services or to allocate any
   * resources that this bundle needs.
   *
   * <p>This method must complete and return to its caller in a timely manner.
   *
   * @param context The execution context of the bundle being started.
   * @throws Exception If this method throws an exception, this bundle is marked as stopped and the
   *     Framework will remove this bundle's listeners, unregister all services registered by this
   *     bundle, and release all services used by this bundle.
   */
  @Override
  public void start(BundleContext context) throws Exception {
    this.context = context;
    initMembers();
    this.activatorLogger.info(
        "Starting APSActivator for bundle '"
            + context.getBundle().getSymbolicName()
            + "' with activatorMode: "
            + this.activatorMode);
    Bundle bundle = context.getBundle();

    List<Class> classEntries = new LinkedList<>();
    if (!this.activatorMode) {
      classEntries.addAll(this.managedInstances.keySet());
    }
    collectClassEntries(bundle, classEntries, "/");

    for (Class entryClass : classEntries) {
      OSGiServiceProvider serviceProvider =
          (OSGiServiceProvider) entryClass.getAnnotation(OSGiServiceProvider.class);
      if (serviceProvider != null && serviceProvider.threadStart()) {
        new StartThread(entryClass, context).start();
      } else {
        handleServiceInstances(entryClass, context);
        handleFieldInjections(entryClass, context);
        handleServiceRegistrations(entryClass, context);
        handleMethods(entryClass, context);
      }
    }
  }
Beispiel #2
0
 /**
  * Handles annotated methods.
  *
  * @param managedClass Used to lookup or create an instance of this class containing the method to
  *     call.
  * @param context The bundle context.
  */
 protected void handleMethods(Class managedClass, BundleContext context) {
   for (Method method : managedClass.getDeclaredMethods()) {
     handleStartupMethods(method, managedClass, context);
     handleShutdownMethods(method, managedClass, context);
     handleListenerMethods(method, managedClass, context);
   }
 }
Beispiel #3
0
  /**
   * This is used to start delayed service publishing. Each tracker of a required service will be
   * calling this method on first service becoming available. When all required services are
   * available the delayed service will be published.
   *
   * @param service The received service.
   * @param serviceReference The reference to the received service.
   * @throws Exception
   */
  @Override
  public void onServiceAvailable(Object service, ServiceReference serviceReference)
      throws Exception {
    this.activatorLogger.info("Received service: " + service.getClass().getName());
    List<Class> uniqueClasses = new LinkedList<>();
    for (Tuple4<APSServiceTracker, Class, Boolean, List<ServiceRegistration>> requiredService :
        this.requiredServices) {
      if (!uniqueClasses.contains(requiredService.t2)) {
        uniqueClasses.add(requiredService.t2);
      }
    }

    for (Class managedClass : uniqueClasses) {
      boolean allRequiredAvailable = true;
      for (Tuple4<APSServiceTracker, Class, Boolean, List<ServiceRegistration>> requiredService :
          this.requiredServices) {
        if (requiredService.t2.equals(managedClass) && !requiredService.t1.hasTrackedService()) {
          allRequiredAvailable = false;
          this.activatorLogger.info(
              "Not all required services are available yet for: " + managedClass.getName());
          break;
        }
      }

      if (allRequiredAvailable) {
        this.activatorLogger.info(
            "All required services are now available for: " + managedClass.getName());
        for (Tuple4<APSServiceTracker, Class, Boolean, List<ServiceRegistration>> requiredService :
            this.requiredServices) {
          if (requiredService.t2.equals(managedClass) && requiredService.t3 == false) {
            this.activatorLogger.info("Registering services for: " + managedClass.getName());
            registerServices(requiredService.t2, this.context, requiredService.t4);
            this.services.addAll(requiredService.t4);
            requiredService.t3 = true;
          }
        }
      }
    }
  }
Beispiel #4
0
  /**
   * Tracks and injects APSServiceTracker directly or as wrapped service instance using the tracker
   * to call the service depending on the field type.
   *
   * @param field The field to inject.
   * @param managedClass Used to lookup or create an instance of this class to inject into.
   * @param context The bundle context.
   */
  protected void handleServiceInjections(Field field, Class managedClass, BundleContext context) {
    OSGiService service = field.getAnnotation(OSGiService.class);
    if (service != null) {
      String trackerKey = field.getType().getName() + service.additionalSearchCriteria();
      APSServiceTracker tracker = this.trackers.get(trackerKey);

      if (tracker == null) {
        tracker =
            new APSServiceTracker<>(
                context, field.getType(), service.additionalSearchCriteria(), service.timeout());
        this.trackers.put(trackerKey, tracker);
      }
      tracker.start();

      List<Object> managedInstances = getManagedInstances(managedClass);
      for (Object managedInstance : managedInstances) {
        if (field.getType().equals(APSServiceTracker.class)) {
          injectObject(managedInstance, tracker, field);
        } else {
          injectObject(managedInstance, tracker.getWrappedService(), field);
        }
      }

      if (service.required() && this.supportsRequired) {
        Tuple4<APSServiceTracker, Class, Boolean, List<ServiceRegistration>> requiredService =
            new Tuple4<>(
                tracker,
                managedClass,
                false,
                (List<ServiceRegistration>) new LinkedList<ServiceRegistration>());
        this.requiredServices.add(requiredService);
      }

      this.activatorLogger.info(
          "Injected tracked service '"
              + field.getType().getName()
              + (service.additionalSearchCriteria().length() > 0
                  ? " " + service.additionalSearchCriteria()
                  : "")
              + "' "
              + "into '"
              + managedClass.getName()
              + "."
              + field.getName()
              + "' for bundle: "
              + context.getBundle().getSymbolicName()
              + " for "
              + managedInstances.size()
              + " instance(s)!");
    }
  }
Beispiel #5
0
  /**
   * Returns a managed instance of a class.
   *
   * @param managedClass The managed class to get instance for.
   * @param size The number of instances.
   */
  protected List<Object> getManagedInstances(Class managedClass, int size) {
    List<Object> managedInstances = this.managedInstances.get(managedClass);
    if (managedInstances == null) {
      managedInstances = new LinkedList<>();
    }

    if (managedInstances.isEmpty()) {
      if (size == -1) throw new IllegalStateException("Expected instances are not available!");
      try {
        for (int i = 0; i < size; i++) {
          Object managedInstance = managedClass.newInstance();
          managedInstances.add(managedInstance);
          this.managedInstances.put(managedClass, managedInstances);
          this.activatorLogger.info(
              "Instantiated '" + managedClass.getName() + "': " + managedInstance);
        }
      } catch (InstantiationException | IllegalAccessException e) {
        throw new APSActivatorException("Failed to instantiate activator managed class!", e);
      }
    }

    return managedInstances;
  }
Beispiel #6
0
  /**
   * Handles publishing of bundle services. If a published service has any dependencies to other
   * services that are marked as required then the publishing is delayed until all required services
   * are available. In this case the service will be unpublished if any of the required services
   * times out.
   *
   * @param managedClass The managed service class to instantiate and register as a service.
   * @param context The bundles context.
   * @throws Exception
   */
  protected void handleServiceRegistrations(final Class managedClass, final BundleContext context)
      throws Exception {
    OSGiServiceProvider serviceProvider =
        (OSGiServiceProvider) managedClass.getAnnotation(OSGiServiceProvider.class);

    if (serviceProvider != null) {
      if (this.requiredServices.isEmpty()) {
        registerServices(managedClass, context, this.services);
      } else {
        for (Tuple4<APSServiceTracker, Class, Boolean, List<ServiceRegistration>> requiredService :
            this.requiredServices) {
          this.activatorLogger.info(
              "Registering for delayed start of '"
                  + managedClass.getName()
                  + "' "
                  + "due to service '"
                  + requiredService.t1.getServiceClass().getName()
                  + "'!");
          requiredService.t1.onActiveServiceAvailable(this);
          requiredService.t1.setOnTimeout(this);
        }
      }
    }
  }
Beispiel #7
0
  /**
   * Handles injections of APSLogger, BundleContext, or other class types with default constructor.
   *
   * @param field The field to inject into.
   * @param managedClass Used to lookup or create an instance of this class to inject into.
   * @param context The bundle context.
   */
  protected void handleInstanceInjections(Field field, Class managedClass, BundleContext context) {
    Managed managed = field.getAnnotation(Managed.class);
    if (managed != null) {
      String namedInstanceKey = managed.name() + field.getType().getName();
      Object namedInstance = this.namedInstances.get(namedInstanceKey);
      if (namedInstance == null) {
        if (field.getType().equals(APSLogger.class)) {
          namedInstance = new APSLogger(System.out);
          if (managed.loggingFor().length() > 0) {
            ((APSLogger) namedInstance).setLoggingFor(managed.loggingFor());
          }
          ((APSLogger) namedInstance).start(context);
        } else if (field.getType().equals(BundleContext.class)) {
          namedInstance = context;
        } else {
          namedInstance = getManagedInstance(field.getType());
        }
        this.namedInstances.put(namedInstanceKey, namedInstance);
      } else {
        this.activatorLogger.info(
            "Got named instance for key '"
                + namedInstanceKey
                + "': "
                + namedInstance.getClass().getName());
      }

      List<Object> managedInstances = getManagedInstances(managedClass);
      for (Object managedInstance : managedInstances) {
        injectObject(managedInstance, namedInstance, field);
      }

      this.activatorLogger.info(
          "Injected '"
              + namedInstance.getClass().getName()
              + "' instance for name '"
              + managed.name()
              + "' "
              + "into '"
              + managedClass.getName()
              + "."
              + field.getName()
              + "' for bundle: "
              + context.getBundle().getSymbolicName()
              + "!");
    }
  }
Beispiel #8
0
  /**
   * This is the first thing done to instantiate all service instances needed, so that they all can
   * be injected later.
   *
   * @param managedClass The manages class to create instances of.
   * @param context The bundles context.
   * @throws Exception
   */
  protected void handleServiceInstances(Class managedClass, BundleContext context)
      throws Exception {
    OSGiServiceProvider serviceProvider =
        (OSGiServiceProvider) managedClass.getAnnotation(OSGiServiceProvider.class);
    if (serviceProvider != null) {
      int noInstances = 1;

      if (serviceProvider.instances().length > 0) {
        noInstances = serviceProvider.instances().length;
      } else if (!serviceProvider.instanceFactoryClass().equals(InstanceFactory.class)) {
        InstanceFactory instanceFactory =
            (InstanceFactory) getManagedInstance(serviceProvider.instanceFactoryClass());
        if (instanceFactory == null) {
          instanceFactory = serviceProvider.instanceFactoryClass().newInstance();
        }
        noInstances = instanceFactory.getPropertiesPerInstance().size();
      }

      // This will just instantiate and cache the number of instances. Right now we don't care
      // about the instances themselves.
      getManagedInstances(managedClass, noInstances);
    }
  }
Beispiel #9
0
  /**
   * Handles methods annotated with @APSBundleStartup.
   *
   * @param method The annotated method to call.
   * @param managedClass Used to lookup or create an instance of this class containing the method to
   *     call.
   * @param context The bundle context.
   */
  protected void handleStartupMethods(
      final Method method, final Class managedClass, final BundleContext context) {
    BundleStart bundleStart = method.getAnnotation(BundleStart.class);
    if (bundleStart != null) {
      if (method.getParameterTypes().length > 0) {
        throw new APSActivatorException(
            "An @BundleStart method must take no parameters! ["
                + managedClass.getName()
                + "."
                + method.getName()
                + "(?)]");
      }

      if (bundleStart.thread()) {
        new Thread(
                new Runnable() {
                  @Override
                  public void run() {
                    try {
                      Object managedInstance = null;
                      if (!Modifier.isStatic(method.getModifiers())) {
                        managedInstance = getManagedInstance(managedClass);
                      }
                      method.invoke(managedInstance, null);

                      APSActivator.this.activatorLogger.info(
                          "Called bundle start method '"
                              + managedClass.getName()
                              + "."
                              + method.getName()
                              + "()' for bundle: "
                              + context.getBundle().getSymbolicName()
                              + "!");
                    } catch (IllegalAccessException iae) {
                      APSActivator.this.activatorLogger.error(
                          "Failed to call start method! ["
                              + managedClass.getName()
                              + "."
                              + method.getName()
                              + "()]",
                          iae);
                    } catch (InvocationTargetException ite) {
                      APSActivator.this.activatorLogger.error(
                          "Failed to call start method! ["
                              + managedClass.getName()
                              + "."
                              + method.getName()
                              + "()]",
                          ite.getCause());
                    } catch (Exception e) {
                      APSActivator.this.activatorLogger.error(
                          "Failed to call start method! ["
                              + managedClass.getName()
                              + "."
                              + method.getName()
                              + "()]",
                          e);
                    }
                  }
                })
            .start();
      } else {
        try {
          Object managedInstance = null;
          if (!Modifier.isStatic(method.getModifiers())) {
            managedInstance = getManagedInstance(managedClass);
          }
          method.invoke(managedInstance, null);

          this.activatorLogger.info(
              "Called bundle start method '"
                  + managedClass.getName()
                  + "."
                  + method.getName()
                  + "()' for bundle: "
                  + context.getBundle().getSymbolicName()
                  + "!");
        } catch (IllegalAccessException iae) {
          throw new APSActivatorException(
              "Failed to call start method! ["
                  + managedClass.getName()
                  + "."
                  + method.getName()
                  + "()]",
              iae);
        } catch (InvocationTargetException ite) {
          throw new APSActivatorException(
              "Failed to call start method! ["
                  + managedClass.getName()
                  + "."
                  + method.getName()
                  + "()]",
              ite.getCause());
        }
      }
    }
  }
Beispiel #10
0
 /**
  * This handles all field injections by delegating to handlers of specific types of field
  * injections.
  *
  * @param managedClass The managed class to inject into.
  * @param context The bundles context.
  */
 protected void handleFieldInjections(Class managedClass, BundleContext context) {
   for (Field field : managedClass.getDeclaredFields()) {
     handleServiceInjections(field, managedClass, context);
     handleInstanceInjections(field, managedClass, context);
   }
 }
Beispiel #11
0
  /**
   * Registers/publishes services annotated with @OSGiServiceProvider.
   *
   * @param managedClass The managed class to instantiate and register as an OSGi service.
   * @param context The bundle context.
   * @param serviceRegs The list to save all service registrations to for later unregistration.
   * @throws Exception
   */
  protected void registerServices(
      Class managedClass, BundleContext context, List<ServiceRegistration> serviceRegs)
      throws Exception {
    OSGiServiceProvider serviceProvider =
        (OSGiServiceProvider) managedClass.getAnnotation(OSGiServiceProvider.class);
    if (serviceProvider != null) {
      List<Tuple3<Properties, Object, List<String>>> serviceInstData = new LinkedList<>();

      if (serviceProvider.properties().length > 0) {
        Tuple3<Properties, Object, List<String>> sd = new Tuple3<>();
        sd.t1 = osgiPropertiesToProperties(serviceProvider.properties());
        serviceInstData.add(sd);
      } else if (serviceProvider.instances().length > 0) {
        for (OSGiServiceInstance serviceInst : serviceProvider.instances()) {
          Tuple3<Properties, Object, List<String>> sd = new Tuple3<>();
          sd.t1 = osgiPropertiesToProperties(serviceInst.properties());
          serviceInstData.add(sd);
        }
      } else if (!serviceProvider.instanceFactoryClass().equals(InstanceFactory.class)) {
        InstanceFactory instanceFactory =
            (InstanceFactory) getManagedInstance(serviceProvider.instanceFactoryClass());
        if (instanceFactory == null) {
          instanceFactory = serviceProvider.instanceFactoryClass().newInstance();
        }
        for (Properties props : instanceFactory.getPropertiesPerInstance()) {
          Tuple3<Properties, Object, List<String>> sd = new Tuple3<>();
          sd.t1 = props;
          serviceInstData.add(sd);
        }
      } else {
        Tuple3<Properties, Object, List<String>> sd = new Tuple3<>();
        sd.t1 = new Properties();
        serviceInstData.add(sd);
      }

      // The number of managedInstances and serviceInstData will always be the same. They both
      // originate
      // from the same information.
      List<Object> managedInstances = getManagedInstances(managedClass);
      for (int i = 0; i < serviceInstData.size(); i++) {

        List<String> serviceAPIs = new LinkedList<>();

        if (serviceProvider.serviceAPIs().length > 0) {
          for (Class svcAPI : serviceProvider.serviceAPIs()) {
            serviceAPIs.add(svcAPI.getName());
          }
        } else if (serviceProvider.instances().length > 0) {
          OSGiServiceInstance svsInstAnn = serviceProvider.instances()[i];
          for (Class svcAPI : svsInstAnn.serviceAPIs()) {
            serviceAPIs.add(svcAPI.getName());
          }
        } else if (!serviceProvider.instanceFactoryClass().equals(InstanceFactory.class)) {
          String svcAPIList =
              serviceInstData.get(i).t1.getProperty(InstanceFactory.SERVICE_API_CLASSES_PROPERTY);
          if (svcAPIList != null) {
            for (String svcAPI : svcAPIList.split(":")) {
              serviceAPIs.add(svcAPI);
            }
          } else {
            Class[] interfaces = managedClass.getInterfaces();
            if (interfaces != null && interfaces.length > 0) {
              serviceAPIs.add(interfaces[0].getName());
            }
          }
        } else {
          Class[] interfaces = managedClass.getInterfaces();
          if (interfaces != null && interfaces.length > 0) {
            serviceAPIs.add(interfaces[0].getName());
          }
        }

        Tuple3<Properties, Object, List<String>> sd = serviceInstData.get(i);
        sd.t3 = serviceAPIs;
        sd.t2 = managedInstances.get(i);
      }

      for (Tuple3<Properties, Object, List<String>> sd : serviceInstData) {
        sd.t1.put(Constants.SERVICE_PID, managedClass.getName());
        if (!sd.t3.isEmpty()) {
          injectInstanceProps(sd.t2, sd.t1);
          for (String svcAPI : sd.t3) {
            ServiceRegistration serviceReg = context.registerService(svcAPI, sd.t2, sd.t1);

            serviceRegs.add(serviceReg);
            this.activatorLogger.info(
                "Registered '"
                    + managedClass.getName()
                    + "' as a service provider of '"
                    + svcAPI
                    + "' for bundle: "
                    + context.getBundle().getSymbolicName()
                    + "!");
          }
        } else {
          throw new IllegalArgumentException(
              "The @OSGiServiceProvider annotated service of class '"
                  + managedClass.getName()
                  + "' does not implement a service interface!");
        }
      }
    }
  }