All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mvysny.fakeservlet.FakeContext.kt Maven / Gradle / Ivy

The newest version!
package com.github.mvysny.fakeservlet

import org.slf4j.LoggerFactory
import java.io.File
import java.io.InputStream
import java.io.Serializable
import java.lang.Exception
import java.net.URL
import java.net.URLConnection
import java.nio.file.Paths
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import jakarta.servlet.*
import jakarta.servlet.descriptor.JspConfigDescriptor
import java.util.concurrent.ConcurrentMap
import kotlin.collections.HashMap

public open class FakeContext : ServletContext, Serializable {
    @Deprecated("Deprecated in Java")
    override fun getServlet(name: String): Servlet? {
        // this method is deprecated since servlet spec 2.1 and should always return null.
        // see javadoc for more details.
        return null
    }

    override fun  createServlet(clazz: Class?): T {
        throw UnsupportedOperationException("not implemented")
    }

    override fun getEffectiveMajorVersion(): Int = 3

    override fun getResource(path: String): URL? {
        // for example @HtmlImport("frontend://reviews-list.html") will expect the resource to be present in the war file,
        // which is typically located in $CWD/src/main/webapp/frontend, so let's search for that first
        val realPath = getRealPath(path)
        if (realPath != null) {
            return File(realPath).toURI().toURL()
        }

        // nope, fall back to class loading.
        //
        // for example @HtmlImport("frontend://bower_components/vaadin-button/src/vaadin-button.html") will try to look up
        // the following resources:
        //
        // 1. /frontend/bower_components/vaadin-button/src/vaadin-button.html
        // 2. /webjars/vaadin-button/src/vaadin-button.html
        //
        // we need to match the latter one to a resource on classpath

        if (path.startsWith("/")) {
            val resource: URL? = Thread.currentThread().contextClassLoader.getResource("META-INF/resources$path")
            if (resource != null) {
                return resource
            }
        }

        if (path.startsWith("/VAADIN/")) {
            // Vaadin 8 exposed directory
            @Suppress("NAME_SHADOWING")
            var path = path
            if (path.contains("..")) {
                // to be able to resolve ThemeResource("../othertheme/img/foo.png") which work from the browser.
                path = Paths.get(path).normalize().toString()
                // convert Windows path separators to Linux ones, so that the follow-up code works
                path = path.replace('\\', '/')
            }
            // reject to serve "/VAADIN/../" resources
            if (path.startsWith("/VAADIN/")) {
                val resource: URL? = Thread.currentThread().contextClassLoader.getResource(path.trimStart('/'))
                if (resource != null) {
                    return resource
                }
            }
        }
        return null
    }

    override fun addListener(className: String) {
        throw UnsupportedOperationException("not implemented")
    }

    override fun  addListener(t: T) {
        throw UnsupportedOperationException("not implemented")
    }

    override fun addListener(listenerClass: Class) {
        throw UnsupportedOperationException("not implemented")
    }

    override fun getClassLoader(): ClassLoader = Thread.currentThread().contextClassLoader

    override fun getAttributeNames(): Enumeration = attributes.keys()

    override fun getMajorVersion(): Int = 3

    override fun log(msg: String) {
        log.error(msg)
    }

    @Deprecated("Deprecated in Java")
    override fun log(exception: Exception, msg: String) {
        log.error(msg, exception)
    }

    override fun log(message: String, throwable: Throwable) {
        log.error(message, throwable)
    }

    override fun getFilterRegistration(filterName: String): FilterRegistration? = filters[filterName]

    private var sessionTrackingModes = defaultSessionTrackingModes

    override fun setSessionTrackingModes(sessionTrackingModes: MutableSet) {
        require(!(sessionTrackingModes.contains(SessionTrackingMode.SSL) && sessionTrackingModes.size > 1)) {
            "sessionTrackingModes: Invalid value $sessionTrackingModes: SSL must not be combined with other values"
        }
        this.sessionTrackingModes = sessionTrackingModes.toSet()
    }

    override fun setInitParameter(name: String, value: String): Boolean = initParameters.putIfAbsent(name, value) == null

    override fun getResourceAsStream(path: String): InputStream? = getResource(path)?.openStream()

    override fun getNamedDispatcher(name: String?): RequestDispatcher {
        throw UnsupportedOperationException("not implemented")
    }

    override fun getFilterRegistrations(): MutableMap = HashMap(filters)

    @Deprecated("Deprecated in Java")
    override fun getServletNames(): Enumeration = Collections.emptyEnumeration()

    override fun getDefaultSessionTrackingModes(): Set = setOf(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)

    override fun getMimeType(file: String): String = URLConnection.guessContentTypeFromName(file) ?: "application/octet-stream"

    override fun declareRoles(vararg roleNames: String) {
        throw UnsupportedOperationException("not implemented")
    }

    override fun  createFilter(clazz: Class): T {
        throw UnsupportedOperationException("not implemented")
    }

    /**
     * [getRealPath] will only resolve `path` in these folders.
     */
    public var realPathRoots: List = listOf("src/main/webapp/frontend", "src/main/webapp")

    override fun getRealPath(path: String): String? {
        for (realPathRoot in realPathRoots) {
            val realPath: File = File(moduleDir, "$realPathRoot/$path").canonicalFile.absoluteFile
            if (realPath.absolutePath.startsWith(File(realPathRoot).absolutePath) && realPath.exists()) {
                return realPath.absolutePath
            }
        }
        return null
    }

    public val initParameters: MutableMap = mutableMapOf()

    override fun getInitParameter(name: String): String? = initParameters[name]

    override fun getMinorVersion(): Int = 0

    override fun getJspConfigDescriptor(): JspConfigDescriptor? = null

    override fun removeAttribute(name: String) {
        attributes.remove(name)
    }

    override fun getServletContextName(): String = "Fake context"

    /**
     * Maps filter name to its registration. All filters registered via [addFilter] will be present here.
     */
    public val filters: ConcurrentMap = ConcurrentHashMap()

    override fun addFilter(filterName: String, className: String): FilterRegistration.Dynamic {
        val reg = FakeFilterRegistration(filterName, className)
        filters[filterName] = reg
        return reg
    }

    override fun addFilter(filterName: String, filter: Filter): FilterRegistration.Dynamic = addFilter(filterName, filter.javaClass)

    override fun addFilter(filterName: String, filterClass: Class): FilterRegistration.Dynamic = addFilter(filterName, filterClass.name)

    override fun getContextPath(): String = ""

    private val sessionCookieConfig = FakeSessionCookieConfig()

    override fun getSessionCookieConfig(): SessionCookieConfig = sessionCookieConfig

    override fun getVirtualServerName(): String = "mock/localhost" // Tomcat returns "Catalina/localhost"

    private var sessionTimeout: Int = 30

    override fun getSessionTimeout(): Int = sessionTimeout

    override fun setSessionTimeout(sessionTimeout: Int) {
        this.sessionTimeout = sessionTimeout
    }

    private var requestCharacterEncoding: String? = null

    override fun getRequestCharacterEncoding(): String? = requestCharacterEncoding

    override fun setRequestCharacterEncoding(encoding: String?) {
        requestCharacterEncoding = encoding
    }

    private var responseCharacterEncoding: String? = null

    override fun getResponseCharacterEncoding(): String? = responseCharacterEncoding

    override fun setResponseCharacterEncoding(encoding: String?) {
        responseCharacterEncoding = encoding
    }

    override fun getContext(uripath: String): ServletContext {
        throw UnsupportedOperationException("not implemented")
    }

    override fun getRequestDispatcher(path: String?): RequestDispatcher {
        throw UnsupportedOperationException("not implemented")
    }

    private val attributes = ConcurrentHashMap()

    override fun getAttribute(name: String): Any? = attributes[name]

    override fun setAttribute(name: String, value: Any?) {
        attributes.putOrRemove(name, value)
    }

    override fun getServletRegistration(servletName: String): ServletRegistration? = null

    override fun  createListener(clazz: Class?): T {
        throw UnsupportedOperationException("not implemented")
    }

    private val _servlets = ConcurrentHashMap()

    override fun addServlet(servletName: String, className: String): ServletRegistration.Dynamic {
        val reg = FakeServletRegistration(servletName, className)
        _servlets[servletName] = reg
        return reg
    }

    override fun addServlet(servletName: String, servlet: Servlet): ServletRegistration.Dynamic = addServlet(servletName, servlet.javaClass)

    override fun addServlet(servletName: String, servletClass: Class): ServletRegistration.Dynamic = addServlet(servletName, servletClass.name)

    override fun addJspFile(servletName: String, jspFile: String): ServletRegistration.Dynamic = FakeServletRegistration(servletName, jspFile)

    @Deprecated("Deprecated in Java")
    override fun getServlets(): Enumeration = Collections.emptyEnumeration()

    override fun getEffectiveMinorVersion(): Int = 0

    override fun getServletRegistrations(): MutableMap = HashMap()

    override fun getResourcePaths(path: String?): MutableSet = mutableSetOf()

    override fun getInitParameterNames(): Enumeration = Collections.enumeration(initParameters.keys)

    override fun getServerInfo(): String = "Mock"

    override fun getEffectiveSessionTrackingModes(): Set = sessionTrackingModes.toSet()

    public companion object {
        @JvmStatic
        private val log = LoggerFactory.getLogger(FakeContext::class.java)
    }
}

internal val moduleDir: File get() {
    var dir = File("").absoluteFile
    // Workaround for https://youtrack.jetbrains.com/issue/IDEA-188466
    // When using $MODULE_DIR$, IDEA will set CWD to, say, karibu-testing/.idea/modules/karibu-testing-v8
    // We need to revert that back to karibu-testing/karibu-testing-v8
    if (dir.absolutePath.contains("/.idea/modules")) {
        dir = File(dir.absolutePath.replace("/.idea/modules", ""))
    }
    return dir
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy