TextApiResource.java

package info.textgrid.services.textapi;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;

import info.textgrid.namespaces.middleware.tgsearch.ResultType;
import info.textgrid.services.textapi.api.Actor;
import info.textgrid.services.textapi.api.Collection;
import info.textgrid.services.textapi.api.ContentItem;
import info.textgrid.services.textapi.api.Item;
import info.textgrid.services.textapi.api.Manifest;
import info.textgrid.services.textapi.api.Repository;
import info.textgrid.services.textapi.api.SequenceItem;
import info.textgrid.services.textapi.api.Title;
import info.textgrid.services.textapi.services.SearchClientService;
import io.quarkus.qute.Template;
import io.quarkus.qute.TemplateInstance;
import io.quarkus.runtime.LaunchMode;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;

@Path("/textapi")
public class TextApiResource {

    @Inject
    SearchClientService searchClient;

    @ConfigProperty(name = "textgrid.host")
    String textgridHost;

    @ConfigProperty(name = "service.url")
    String serviceUrl;

    @ConfigProperty(name = "validator.url")
    String validatorUrl;

    @ConfigProperty(name = "quarkus.application.version")
    String version;

    @Inject
    LaunchMode launchMode;

    @Inject
    Template index;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}/manifest.json")
    @Operation(
        summary = "Generate a TextAPI manifest",
        description = "Use TextGridURI to list all items of an aggregation as TextAPI Items, "
                    + "utilizing the aggregator for TEI->HTML transformation"
    )
    public Manifest manifest(
        @Parameter(
            description = "the TextGridURI to generate a manifest for",
            example = "textgrid:wp1j.0"
        )
        @PathParam("id") String id) {
        
        var meta = searchClient.infoQuery().getMetadata(id);
        var label = meta.getResult().get(0).getObject().getGeneric().getProvided().getTitle().get(0);
        var format = meta.getResult().get(0).getObject().getGeneric().getProvided().getFormat();
        
        var r = new Repository().setId(id);
        var m = new Manifest().setId(serviceUrl + "/" + id + "/manifest.json").setLabel(label).addRepository(r);

        // every item of an for aggregations 
        if(format.equals("text/tg.aggregation+xml")) {
            for (ResultType res: searchClient.navigationQuery().listAggregation(id).getResult()) {
                var s = new SequenceItem()
                    .setId(serviceUrl + "/" + res.getTextgridUri() + "/item.json")
                    .setType("item")
                    .setLabel(res.getObject().getGeneric().getProvided().getTitle().get(0));
                m.addSequenceItem(s);
            }
        } else {
            var s = new SequenceItem().setId(serviceUrl + "/" + id + "/item.json").setLabel(label);
            m.addSequenceItem(s);
        }
        return m;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}/item.json")
    @Operation(
        summary = "Generate a TextAPI item",
        description = "Get aggregator URL for given TextGridUri for TEI -> HTML transformation"
    )
    public Item item(
        @Parameter(
            description= "textgridUri of a single item (normally listed inside a manifest)",
            example = "textgrid:wmd3.0"
        )
        @PathParam("id") String id) {
        
        var _id = serviceUrl + "/" + id + "/item.json";
        var contentItem = new ContentItem().setUrl(textgridHost + "/1.0/aggregator/html/" + id + "?embedded=true");
        // TODO: lang from textgrid metadata, what if not set? set to und (undetermined)
        // https://de.wikipedia.org/wiki/ISO_639#Spezielle_Kennungen
        var item = new Item().addContent(contentItem).setId(_id).addLang("und");

        return item;
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/info")
    @Operation(
        summary = "Build info & config of this service"
    )
    public String info() {
        return """
            tg-textapi %s
            textgrid host: %s
            devmode: %s
            """.formatted(version, textgridHost, launchMode.isDevOrTest());
    }

    @GET
    @Produces(MediaType.TEXT_HTML)
    @Path("/")
    @Operation(hidden = true) // hide operation from OpenAPI
    public TemplateInstance index() {
        return index.data("version", version)
                    .data("serviceUrl", serviceUrl)
                    .data("validatorUrl", validatorUrl)
                    .data("devmode", launchMode.isDevOrTest())
                    ;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/search/collection.json")
    public Collection search(@QueryParam("q") String query) {
        return searchToCollection(query);
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/search/{q}/collection.json")
    public Collection searchPath(@PathParam("q") String query) {
        return searchToCollection(query);
    }

    Collection searchToCollection(String query) {
        var results = searchClient.searchQuery().setQuery(query).execute();

        var description = "Search results for " + query;
        var title = new Title().setTitle("Query: "  + query);
        var collector = new Actor().addRole("collector").setName("you via tgsearch").setId("yoursearch");
        var collection = new Collection()
                    .setId("todo")
                    .setDescription(description)
                    .addTitle(title)
                    .addCollector(collector);

        for (ResultType res: results.getResult()) {
            var id = res.getObject().getGeneric().getGenerated().getTextgridUri().getValue();
            var SequenceItem = new SequenceItem()
                .setId(serviceUrl + "/" + id + "/manifest.json")
                .setType("manifest")
                .setLabel(res.getObject().getGeneric().getProvided().getTitle().get(0));
            collection.addSequenceItem(SequenceItem);
        }

        return collection;
    }

}