/** * 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); } } }
/** * 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); } }
/** * 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); } } } }
/** * 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!"); } } } }