event based file processing

- use VirtualFileListener to wait for ui xml file updates
- optimize imports
This commit is contained in:
Mikhail Mutcianko
2014-07-18 18:08:14 +04:00
committed by Yan Zhulanow
parent 208735d92e
commit d557fa8d5d
2 changed files with 50 additions and 13 deletions
@@ -10,6 +10,11 @@ import org.jetbrains.kotlin.psi.JetFile
import javax.xml.parsers.SAXParser
import java.util.HashMap
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.VirtualFileAdapter
import com.intellij.openapi.vfs.VirtualFileEvent
import com.intellij.openapi.project.Project
import java.util.concurrent.ConcurrentLinkedQueue
abstract class AndroidUIXmlParser {
@@ -24,9 +29,13 @@ abstract class AndroidUIXmlParser {
val saxParser = initSAX()
val fileCache = HashMap<File, String>()
val fileCache = HashMap<VirtualFile, String>()
var lastCachedPsi: JetFile? = null
val fileModificationTime = HashMap<File, Long>()
val fileModificationTime = HashMap<VirtualFile, Long>()
val filesToProcess = ConcurrentLinkedQueue<VirtualFile>()
var listenerSetUp = false
volatile var invalidateCaches = false
public fun parseToString(): String? {
val cacheState = doParse()
@@ -37,7 +46,7 @@ abstract class AndroidUIXmlParser {
public fun parseToPsi(project: Project): JetFile? {
val cacheState = doParse()
if (cacheState == null) return null
return if (cacheState === CacheAction.MISS) {
return if (cacheState == CacheAction.MISS || lastCachedPsi == null) {
try {
val psiFile = JetPsiFactory(project).createFile(renderString())
lastCachedPsi = psiFile
@@ -84,20 +93,20 @@ abstract class AndroidUIXmlParser {
return kw
}
private fun parseSingleFileWithCache(file: File): Pair<String, CacheAction> {
private fun parseSingleFileWithCache(file: VirtualFile): Pair<String, CacheAction> {
val lastRecorded = fileModificationTime[file] ?: -1
if (file.lastModified() > lastRecorded)
if (file.getModificationStamp() > lastRecorded)
return Pair(parseSingleFile(file), CacheAction.MISS)
else
return Pair(fileCache[file]!!, CacheAction.HIT)
}
private fun parseSingleFile(file: File): String {
private fun parseSingleFile(file: VirtualFile): String {
val ids: MutableCollection<AndroidWidget> = ArrayList()
val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) })
fileModificationTime[file] = file.lastModified()
fileModificationTime[file] = file.getModificationStamp()
try {
saxParser.parse(FileInputStream(file), handler)
saxParser.parse(file.getInputStream()!!, handler)
val res = produceKotlinProperties(KotlinStringWriter(), ids).toString()
fileCache[file] = res
return res
@@ -109,11 +118,14 @@ abstract class AndroidUIXmlParser {
private fun doParse(): CacheAction? {
if (searchPath == null || searchPath == "") return null
val files = searchForUIXml(searchPath!!)
lazySetupFileListener()
if (invalidateCaches) invalidateCaches()
var overallCacheMiss = false
for (file in files) {
val res = parseSingleFileWithCache(file)
var file = filesToProcess.poll()
while (file != null) {
val res = parseSingleFileWithCache(file!!)
overallCacheMiss = overallCacheMiss or (res.second == CacheAction.MISS)
file = filesToProcess.poll()
}
return if (overallCacheMiss) CacheAction.MISS else CacheAction.HIT
}
@@ -129,6 +141,33 @@ abstract class AndroidUIXmlParser {
fileCache.clear()
fileModificationTime.clear()
lastCachedPsi = null
invalidateCaches = false
}
private fun lazySetupFileListener() {
if (listenerSetUp) return
val fileManager = VirtualFileManager.getInstance()
val watchDir = fileManager.findFileByUrl("file://" + searchPath)
filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0))
fileManager.addVirtualFileListener(object : VirtualFileAdapter() {
override fun contentsChanged(event: VirtualFileEvent) {
if (event.getParent() == watchDir)
filesToProcess.add(event.getFile())
}
override fun fileCreated(event: VirtualFileEvent) {
if (event.getParent() == watchDir)
super<VirtualFileAdapter>.fileCreated(event)
}
override fun fileDeleted(event: VirtualFileEvent) {
if (event.getParent() == watchDir) {
// ignore potential synchronisation issues - it doesn't really matter if invalidation and
// file processing will be handled in different passes
invalidateCaches = true
filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0))
}
}
})
listenerSetUp = true
}
private fun produceKotlinProperties(kw: KotlinStringWriter, ids: Collection<AndroidWidget>): StringBuffer {
@@ -1,6 +1,4 @@
package org.jetbrains.jet.lang.resolve.android
import com.intellij.openapi.project.Project
class CliAndroidUIXmlParser(override val searchPath: String?): AndroidUIXmlParser()