Skip to content

Instantly share code, notes, and snippets.

@tux19
Last active July 13, 2022 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tux19/4ea019f7ef333f0036ef3a8cf4b6019e to your computer and use it in GitHub Desktop.
Save tux19/4ea019f7ef333f0036ef3a8cf4b6019e to your computer and use it in GitHub Desktop.
Custom HostConnectionAccessor for Pocketknife QueryDSL
import java.lang.reflect.Field
import java.sql.Connection
import com.atlassian.activeobjects.external.ActiveObjects
import com.atlassian.activeobjects.spi.{DatabaseType, TenantAwareDataSourceProvider}
import com.atlassian.sal.api.rdbms.ConnectionCallback
import com.atlassian.tenancy.api.TenantAccessor
import javax.inject.{Inject, Named}
import javax.sql.DataSource
import org.osgi.framework.FrameworkUtil
import org.springframework.context.annotation.Primary
@Primary
@Named
class HostConnectionAccessor @Inject()() extends Logging{
//todo handle such situations better, on plugin start the values should never be null
protected val bundleContext = scala.Option(FrameworkUtil.getBundle(classOf[ActiveObjects])).map(_.getBundleContext).orNull
protected val tenantAccessor = scala.Option(bundleContext).map(
_.getService(bundleContext
.getServiceReference(classOf[TenantAccessor].getName))
.asInstanceOf[TenantAccessor]).orNull
protected val dataSourceProvider = scala.Option(bundleContext).map(
_.getService(bundleContext
.getServiceReference(classOf[TenantAwareDataSourceProvider].getName))
.asInstanceOf[TenantAwareDataSourceProvider]).orNull
def getSchemaName: Option[String] = {
val tenant = tenantAccessor.getAvailableTenants.iterator().next()
val src = dataSourceProvider.getDataSource(tenant)
val con = src.getConnection
try {
dataSourceProvider.getDatabaseType(tenant) match {
case DatabaseType.H2 =>
// nasty get internal session of connection object via reflection
val metadataCon = con.getMetaData.getConnection
try {
extractSchemaNameFromConnection(metadataCon)
} catch {
case e: NoSuchFieldException =>
// BB 7.4 has no session on metadataCon, but a delegate field with the session.
val delegateField = getField(metadataCon.getClass,"delegate")
delegateField.setAccessible(true)
val delegateCon = delegateField.get(metadataCon).asInstanceOf[Connection]
extractSchemaNameFromConnection(delegateCon)
}
case DatabaseType.POSTGRESQL => Option(con.getSchema)
case DatabaseType.MYSQL => Option(con.getCatalog)
case DatabaseType.ORACLE => Option(con.getMetaData.getUserName)
case _ => Option(con.getSchema)
}
} finally {
con.close()
}
}
def getDataSource: DataSource = dataSourceProvider.getDataSource(tenantAccessor.getAvailableTenants.iterator().next())
def getDatabaseType: DatabaseType = dataSourceProvider.getDatabaseType(tenantAccessor.getAvailableTenants.iterator().next())
def execute[A](b: Boolean, b1: Boolean, connectionCallback: ConnectionCallback[A]): A = throw new RuntimeException
private def extractSchemaNameFromConnection(con: Connection) = {
val sessionField = con.getClass.getDeclaredField("session")
sessionField.setAccessible(true)
val session = sessionField.get(con)
val schemaField = session.getClass.getDeclaredField("currentSchemaName")
schemaField.setAccessible(true)
Option(schemaField.get(session).asInstanceOf[String])
}
/**
* Returns the first {@link Field} in the hierarchy for the specified name
*/
def getField(clazz: Class[_], name: String): Field = {
var field: Field = null
var currentClazz = clazz
while ( {
currentClazz != null && field == null
}) {
try {
field = currentClazz.getDeclaredField(name)
}
catch {
case e: Exception =>
}
currentClazz = currentClazz.getSuperclass
}
field
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment