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

de.richtercloud.jsf.validation.service.web.Validation.kt Maven / Gradle / Ivy

/**
 * Copyright 2018-2021 Karl-Philipp Richter
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package de.richtercloud.jsf.validation.service.web

import com.natpryce.hamkrest.Matcher
import de.richtercloud.jsf.validation.service.ValidatorMessage
import java.util.HashMap
import de.richtercloud.jsf.validation.service.MemoryValidationService
import kotlin.Throws
import java.io.IOException
import java.net.URISyntaxException
import de.richtercloud.jsf.validation.service.ValidatorMessageSeverity
import org.slf4j.LoggerFactory
import org.xml.sax.SAXException
import java.io.Serializable
import javax.faces.context.FacesContext
import java.net.MalformedURLException
import java.net.URI
import java.net.URL
import javax.faces.event.AjaxBehaviorEvent
import java.util.HashSet
import javax.enterprise.context.ApplicationScoped
import javax.inject.Named
import javax.servlet.http.HttpServletRequest

/**
 * There's currently no support for an explicit failure (e.g. of page load)
 * after a validation failure since that requires a complex mechanism of sending
 * an error which isn't trivial in JSF and listing the validation failure
 * messages is way sufficient and everything beyond that yagni.
 *
 * @author richter
 */
@Named
@ApplicationScoped
class Validation : Serializable {
    /**
     * Maps request servlet path to the set of discarded messages for this path.
     * Doesn't use URI as keys because the same resource can be accessed with
     * possibly more than URI.
     */
    private var discardMap: MutableMap> = HashMap()
    private val validationService = MemoryValidationService(true)
    fun getDiscardMap(): Map> {
        return discardMap
    }

    fun setDiscardMap(discardMap: MutableMap>) {
        this.discardMap = discardMap
    }

    @Throws(IOException::class, URISyntaxException::class, SAXException::class)
    fun validate(
        minimumLevel: ValidatorMessageSeverity,
        ignores: Matcher
    ): List {
        val requestURL = requestURL
        LOGGER.trace("request URL: ${requestURL.toExternalForm()}")
        val validationURL = URI(
            requestURL.protocol,
            requestURL.authority,
            requestURL.path,
            "$SKIP_VALIDATE_KEY=true",
            null
        )
        LOGGER.trace("validation URL: ${validationURL}")
        val retValue = validationService.validateMessages(
            validationURL,
            minimumLevel,
            ignores
        ).toMutableList()
        val requestURIDiscards: Set? =
            discardMap[FacesContext.getCurrentInstance().externalContext.requestServletPath]
        LOGGER.trace("requestURIDiscards: $requestURIDiscards")
        if (requestURIDiscards != null) {
            for (requestURIDiscard in requestURIDiscards) {
                while (retValue.contains(requestURIDiscard)) {
                    retValue.remove(requestURIDiscard)
                }
            }
        }
        return retValue
    }

    @Throws(URISyntaxException::class, MalformedURLException::class)
    fun discardValidationMessage(event: AjaxBehaviorEvent) {
        val message = event.component.attributes["message"] as ValidatorMessage?
        var requestURIDiscards = discardMap[FacesContext.getCurrentInstance().externalContext.requestServletPath]
        if (requestURIDiscards == null) {
            requestURIDiscards = HashSet()
            discardMap[FacesContext.getCurrentInstance().externalContext.requestServletPath] = requestURIDiscards
        }
        requestURIDiscards.add(message)
    }

    @Throws(URISyntaxException::class, IOException::class, SAXException::class)
    fun discardAll(event: AjaxBehaviorEvent) {
        val minimumLevel = event.component.attributes["minimumLevel"] as ValidatorMessageSeverity
        val ignores = event.component.attributes["ignores"] as Matcher
        var requestURIDiscards = discardMap[FacesContext.getCurrentInstance().externalContext.requestServletPath]
        if (requestURIDiscards == null) {
            requestURIDiscards = HashSet()
            discardMap[FacesContext.getCurrentInstance().externalContext.requestServletPath] = requestURIDiscards
        }
        val messages = validate(
            minimumLevel,
            ignores
        )
        requestURIDiscards.addAll(messages)
    }

    fun resetDiscards(event: AjaxBehaviorEvent?) {
        discardMap.clear()
    }

    @Throws(MalformedURLException::class, URISyntaxException::class)
    fun forceRevalidation(event: AjaxBehaviorEvent?) {
        validationService.clearCache()
    }

    /**
     * Any combination of creating URLs from URIs and using different string
     * representations create different URLs and URIs (absolute/relative,
     * with/without welcome page in the path).
     *
     * @return the request URL
     */
    @get:Throws(MalformedURLException::class)
    private val requestURL: URL
        private get() = URL((FacesContext.getCurrentInstance().externalContext.request as HttpServletRequest).requestURL.toString())

    companion object {
        private const val serialVersionUID = 1L
        private val LOGGER = LoggerFactory.getLogger(Validation::class.java)
        const val SKIP_VALIDATE_KEY = "skipValidate"
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy