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

net.nemerosa.ontrack.boot.ProjectSearchProvider.kt Maven / Gradle / Ivy

There is a newer version: 4.4.5
Show newest version
package net.nemerosa.ontrack.boot

import com.fasterxml.jackson.databind.JsonNode
import net.nemerosa.ontrack.model.events.Event
import net.nemerosa.ontrack.model.events.EventFactory
import net.nemerosa.ontrack.model.events.EventListener
import net.nemerosa.ontrack.model.structure.*
import net.nemerosa.ontrack.ui.controller.URIBuilder
import net.nemerosa.ontrack.ui.support.AbstractSearchProvider
import org.springframework.stereotype.Component
import java.util.regex.Pattern

/**
 * Minimum length of a token to compare with project names by content.
 */
const val PROJECT_SEARCH_PROVIDER_TOKEN_MIN_LENGTH = 3

/**
 * Projects search index name
 */
const val PROJECT_SEARCH_INDEX = "projects"

/**
 * Search result type
 */
const val PROJECT_SEARCH_RESULT_TYPE = "project"

/**
 * Matches against projects either by name or by content if the
 * search token is at least [PROJECT_SEARCH_PROVIDER_TOKEN_MIN_LENGTH] characters long.
 */
@Component
class ProjectSearchProvider(
        uriBuilder: URIBuilder,
        private val structureService: StructureService,
        private val searchIndexService: SearchIndexService
) : AbstractSearchProvider(uriBuilder), SearchIndexer, EventListener {

    override val searchResultType = SearchResultType(
            feature = CoreExtensionFeature.INSTANCE.featureDescription,
            id = PROJECT_SEARCH_RESULT_TYPE,
            name = "Project",
            description = "Project name in Ontrack"
    )

    override fun isTokenSearchable(token: String): Boolean {
        return Pattern.matches(NameDescription.NAME, token)
    }

    override fun search(token: String): Collection {
        return structureService.projectList
                .filter { project ->
                    project.name.equals(token, true) ||
                            (token.length >= PROJECT_SEARCH_PROVIDER_TOKEN_MIN_LENGTH &&
                                    project.name.contains(token, true)
                                    )
                }
                .map { project ->
                    SearchResult(
                            title = project.entityDisplayName,
                            description = "",
                            uri = uriBuilder.getEntityURI(project),
                            page = uriBuilder.getEntityPage(project),
                            accuracy = 100.0,
                            type = searchResultType
                    )
                }
    }

    override val indexerName: String = "Projects"

    override val indexName: String = PROJECT_SEARCH_INDEX

    override val indexMapping: SearchIndexMapping = indexMappings {
        +ProjectSearchItem::name to keyword { scoreBoost = 3.0 }
        +ProjectSearchItem::description to text()
    }

    override fun indexAll(processor: (ProjectSearchItem) -> Unit) {
        structureService.projectList.forEach { project ->
            processor(project.asSearchItem())
        }
    }

    override fun toSearchResult(id: String, score: Double, source: JsonNode): SearchResult? {
        return structureService.findProjectByID(ID.of(id.toInt()))?.run {
            SearchResult(
                    title = entityDisplayName,
                    description = description ?: "",
                    uri = uriBuilder.getEntityURI(this),
                    page = uriBuilder.getEntityPage(this),
                    accuracy = score,
                    type = searchResultType
            )
        }
    }

    override fun onEvent(event: Event) {
        when (event.eventType) {
            EventFactory.NEW_PROJECT -> {
                val project = event.getEntity(ProjectEntityType.PROJECT)
                searchIndexService.createSearchIndex(this, project.asSearchItem())
            }
            EventFactory.UPDATE_PROJECT -> {
                val project = event.getEntity(ProjectEntityType.PROJECT)
                searchIndexService.updateSearchIndex(this, project.asSearchItem())
            }
            EventFactory.DELETE_PROJECT -> {
                val projectId = event.getIntValue("project_id")
                searchIndexService.deleteSearchIndex(this, projectId)
            }
        }
    }

    private fun Project.asSearchItem() = ProjectSearchItem(this)

}

class ProjectSearchItem(
        override val id: String,
        val name: String,
        val description: String
) : SearchItem {
    constructor(project: Project) : this(
            id = project.id.toString(),
            name = project.name,
            description = project.description ?: ""
    )

    override val fields: Map = mapOf(
            "name" to name,
            "description" to description
    )

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy