Bitbucket OsgiPlugin never resolved AuditService

Hi. I’m having an issue trying to use AuditService in a Bitbucket plugin and already tried a lot of different approaches:

ERROR [spring-startup]  c.a.plugin.osgi.factory.OsgiPlugin Plugin 'packagename' never resolved service '&auditService' with filter '(&(objectClass=com.atlassian.bitbucket.audit
.AuditService)(objectClass=com.atlassian.bitbucket.audit.AuditService))'

The service is imported like this (shortened):

import com.atlassian.bitbucket.audit.AuditService;

@ExportAsService{MyService.class}
@Named("myService")
public class MyService {
  @ComponentImport
  private final AuditService auditService;

  @Inject
  public MyService(final AuditService auditService) {
    this.auditService = auditService
  } 
}

I already tried using the AuditService as component without Atlassian Spring Scanner as described here: https://www.j-tricks.com/tutorials/component-import-gotchas-nosuchbeandefinitionexception or a declaring DynamicImport as described here: How do I use Bitbucket AuditService in an v2 add-on? but without any luck.

Does anyone have an idea how to import or make this service usable to retrieve audit logs?

Hi

I ran into the same problem. After inspecting Bitbucket’s source code, I’m quite sure it is not exposing the service correctly. No idea if this is intentional or not, but as it is, it cannot be injected.

The class itself is instantiated and can be accessed by some OSGI magic over the BundleContext and trough the ApplicationContext.

Hopefully this helps those that run into the same problem!

Hi @christian.ott

Thank you for your reply! Could post some code snippets for this OSGi magic? That would be really helpful! :slight_smile:

Sure! The code is in Scala but it should be easy to adapt:


// Access some BundleContext, could be any but I knew that AO worked :D
val bndCtx: BundleContext = Option(FrameworkUtil.getBundle(classOf[ActiveObjects])).map(_.getBundleContext).orNull
 
// access all bundle references that export an ApplicationContext service (which every Bundle does)
// and have the name of the desired bundle
val bRefs = bndCtx.getAllServiceReferences("org.springframework.context.ApplicationContext",
                                           "(org.springframework.context.service.name=com.atlassian.bitbucket.server.bitbucket-audit)")
 
// get the first service reference, get its service from the bundle context, and cast to the desired class
val ac = bndCtx.getService(bRefs(0)).asInstanceOf[ApplicationContext]
 
// the application context of the bundle gives access to all beans in the bundle, e.g. the auditService
val auditService = ac.getBean("auditService").asInstanceOf[AuditService]

You can do all kinds of stuff this way… but… it is against the spirit of OSGI’s bundle separation and probably should be used with care :crazy_face:

1 Like