Add prototype of global action support

This commit is contained in:
Naoki Takezoe
2015-02-07 13:12:05 +09:00
parent 73c76a5a88
commit 7e77398645
6 changed files with 138 additions and 26 deletions

View File

@@ -1,4 +1,4 @@
import _root_.servlet.{BasicAuthenticationFilter, TransactionFilter} import _root_.servlet.{BasicAuthenticationFilter, TransactionFilter, PluginActionFilter}
import app._ import app._
//import jp.sf.amateras.scalatra.forms.ValidationJavaScriptProvider //import jp.sf.amateras.scalatra.forms.ValidationJavaScriptProvider
import org.scalatra._ import org.scalatra._
@@ -12,6 +12,8 @@ class ScalatraBootstrap extends LifeCycle {
context.getFilterRegistration("transactionFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*") context.getFilterRegistration("transactionFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*")
context.addFilter("basicAuthenticationFilter", new BasicAuthenticationFilter) context.addFilter("basicAuthenticationFilter", new BasicAuthenticationFilter)
context.getFilterRegistration("basicAuthenticationFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/git/*") context.getFilterRegistration("basicAuthenticationFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/git/*")
context.addFilter("pluginActionFilter", new PluginActionFilter)
context.getFilterRegistration("pluginActionFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*")
// Register controllers // Register controllers
context.mount(new AnonymousAccessController, "/*") context.mount(new AnonymousAccessController, "/*")

View File

@@ -2,9 +2,12 @@ package plugin
import java.io.{FilenameFilter, File} import java.io.{FilenameFilter, File}
import java.net.URLClassLoader import java.net.URLClassLoader
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import service.RepositoryService.RepositoryInfo
import util.Directory._ import util.Directory._
import util.JDBCUtil._
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
@@ -12,6 +15,8 @@ class PluginRegistry {
private val plugins = new ListBuffer[PluginInfo] private val plugins = new ListBuffer[PluginInfo]
private val javaScripts = new ListBuffer[(String, String)] private val javaScripts = new ListBuffer[(String, String)]
private val globalActions = new ListBuffer[GlobalAction]
private val repositoryActions = new ListBuffer[RepositoryAction]
def addPlugin(pluginInfo: PluginInfo): Unit = { def addPlugin(pluginInfo: PluginInfo): Unit = {
plugins += pluginInfo plugins += pluginInfo
@@ -19,17 +24,51 @@ class PluginRegistry {
def getPlugins(): List[PluginInfo] = plugins.toList def getPlugins(): List[PluginInfo] = plugins.toList
def addGlobalAction(method: String, path: String)(f: (HttpServletRequest, HttpServletResponse) => Any): Unit = {
globalActions += GlobalAction(method.toLowerCase, path, f)
}
//def getGlobalActions(): List[GlobalAction] = globalActions.toList
def getGlobalAction(method: String, path: String): Option[(HttpServletRequest, HttpServletResponse) => Any] = {
globalActions.find { globalAction =>
globalAction.method == method.toLowerCase && path.matches(globalAction.path)
}.map(_.function)
}
def addRepositoryAction(method: String, path: String)(f: (HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any): Unit = {
repositoryActions += RepositoryAction(method.toLowerCase, path, f)
}
//def getRepositoryActions(): List[RepositoryAction] = repositoryActions.toList
def getRepositoryAction(method: String, path: String): Option[(HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any] = {
// TODO
null
}
def addJavaScript(path: String, script: String): Unit = { def addJavaScript(path: String, script: String): Unit = {
javaScripts += Tuple2(path, script) javaScripts += Tuple2(path, script)
} }
def getJavaScripts(): List[(String, String)] = javaScripts.toList //def getJavaScripts(): List[(String, String)] = javaScripts.toList
def getJavaScript(currentPath: String): Option[String] = { def getJavaScript(currentPath: String): Option[String] = {
println(currentPath) javaScripts.find(x => currentPath.matches(x._1)).map(_._2)
getJavaScripts().find(x => currentPath.matches(x._1)).map(_._2)
} }
private case class GlobalAction(
method: String,
path: String,
function: (HttpServletRequest, HttpServletResponse) => Any
)
private case class RepositoryAction(
method: String,
path: String,
function: (HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any
)
} }
object PluginRegistry { object PluginRegistry {
@@ -40,24 +79,37 @@ object PluginRegistry {
def apply(): PluginRegistry = instance def apply(): PluginRegistry = instance
def initialize(): Unit = { def initialize(conn: java.sql.Connection): Unit = {
new File(PluginHome).listFiles(new FilenameFilter { val pluginDir = new File(PluginHome)
override def accept(dir: File, name: String): Boolean = name.endsWith(".jar") if(pluginDir.exists && pluginDir.isDirectory){
}).foreach { pluginJar => pluginDir.listFiles(new FilenameFilter {
val classLoader = new URLClassLoader(Array(pluginJar.toURI.toURL), Thread.currentThread.getContextClassLoader) override def accept(dir: File, name: String): Boolean = name.endsWith(".jar")
try { }).foreach { pluginJar =>
val plugin = classLoader.loadClass("Plugin").newInstance().asInstanceOf[Plugin] val classLoader = new URLClassLoader(Array(pluginJar.toURI.toURL), Thread.currentThread.getContextClassLoader)
plugin.initialize(instance) try {
instance.addPlugin(PluginInfo( val plugin = classLoader.loadClass("Plugin").newInstance().asInstanceOf[Plugin]
pluginId = plugin.pluginId, plugin.initialize(instance)
pluginName = plugin.pluginName, instance.addPlugin(PluginInfo(
version = plugin.version, pluginId = plugin.pluginId,
description = plugin.description, pluginName = plugin.pluginName,
pluginClass = plugin version = plugin.version,
)) description = plugin.description,
} catch { pluginClass = plugin
case e: Exception => { ))
logger.error(s"Error during plugin initialization", e)
conn.find("SELECT * FROM PLUGIN WHERE PLUGIN_ID = ?", plugin.pluginId)(_.getString("VERSION")) match {
// Update if the plugin is already registered
case Some(currentVersion) => conn.update("UPDATE PLUGIN SET VERSION = ? WHERE PLUGIN_ID = ?", plugin.version, plugin.pluginId)
// Insert if the plugin does not exist
case None => conn.update("INSERT INTO PLUGIN (PLUGIN_ID, VERSION) VALUES (?, ?)", plugin.pluginId, plugin.version)
}
// TODO Migration
} catch {
case e: Exception => {
logger.error(s"Error during plugin initialization", e)
}
} }
} }
} }

View File

@@ -13,6 +13,8 @@ import org.eclipse.jgit.api.Git
import util.Directory import util.Directory
import plugin._ import plugin._
import scala.slick.jdbc.meta.MBestRowIdentifierColumn.Scope.Session
object AutoUpdate { object AutoUpdate {
/** /**
@@ -103,8 +105,10 @@ object AutoUpdate {
conn.update("UPDATE ACTIVITY SET ADDITIONAL_INFO = ? WHERE ACTIVITY_ID = ?", newInfo, rs.getInt("ACTIVITY_ID")) conn.update("UPDATE ACTIVITY SET ADDITIONAL_INFO = ? WHERE ACTIVITY_ID = ?", newInfo, rs.getInt("ACTIVITY_ID"))
} }
} }
FileUtils.deleteDirectory(Directory.getPluginCacheDir()) ignore {
FileUtils.deleteDirectory(new File(Directory.PluginHome)) FileUtils.deleteDirectory(Directory.getPluginCacheDir())
//FileUtils.deleteDirectory(new File(Directory.PluginHome))
}
} }
}, },
new Version(2, 2), new Version(2, 2),
@@ -235,10 +239,12 @@ class AutoUpdateListener extends ServletContextListener {
} }
} }
logger.debug("End schema update") logger.debug("End schema update")
// Load plugins
PluginRegistry.initialize(conn)
} }
// Load plugins
PluginRegistry.initialize()
} }
def contextDestroyed(sce: ServletContextEvent): Unit = { def contextDestroyed(sce: ServletContextEvent): Unit = {

View File

@@ -0,0 +1,38 @@
package servlet
import javax.servlet._
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
import play.twirl.api.Html
import plugin.PluginRegistry
class PluginActionFilter extends Filter {
def init(config: FilterConfig) = {}
def destroy(): Unit = {}
def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = (req, res) match {
case (req: HttpServletRequest, res: HttpServletResponse) => {
val method = req.getMethod.toLowerCase
val path = req.getRequestURI.substring(req.getContextPath.length)
val registry = PluginRegistry()
registry.getGlobalAction(method, path).map { action =>
action(req, res) match {
// TODO to be type classes?
case x: String =>
res.setContentType("text/plain; charset=UTF-8")
res.getWriter.write(x)
res.getWriter.flush()
case x: Html =>
res.setContentType("text/html; charset=UTF-8")
res.getWriter.write(x.body)
res.getWriter.flush()
}
}.getOrElse {
chain.doFilter(req, res)
}
}
}
}

View File

@@ -37,4 +37,10 @@ object ControlUtil {
def using[T](treeWalk: TreeWalk)(f: TreeWalk => T): T = def using[T](treeWalk: TreeWalk)(f: TreeWalk => T): T =
try f(treeWalk) finally treeWalk.release() try f(treeWalk) finally treeWalk.release()
def ignore[T](f: => Unit): Unit = try {
f
} catch {
case e: Exception => ()
}
} }

View File

@@ -18,6 +18,14 @@ object JDBCUtil {
} }
} }
def find[T](sql: String, params: Any*)(f: ResultSet => T): Option[T] = {
execute(sql, params: _*){ stmt =>
using(stmt.executeQuery()){ rs =>
if(rs.next) Some(f(rs)) else None
}
}
}
def select[T](sql: String, params: Any*)(f: ResultSet => T): Seq[T] = { def select[T](sql: String, params: Any*)(f: ResultSet => T): Seq[T] = {
execute(sql, params: _*){ stmt => execute(sql, params: _*){ stmt =>
using(stmt.executeQuery()){ rs => using(stmt.executeQuery()){ rs =>