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"
}
}