org.terasology.web.servlet.ModuleServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.terasology.web.servlet.ModuleServlet.java

Source

/*
 * Copyright 2015 MovingBlocks
 *
 * 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 org.terasology.web.servlet;

import java.io.OutputStreamWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;

import org.glassfish.jersey.server.mvc.Viewable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.module.Module;
import org.terasology.module.ModuleMetadata;
import org.terasology.module.ModuleMetadataJsonAdapter;
import org.terasology.module.RemoteModuleExtension;
import org.terasology.naming.Name;
import org.terasology.naming.Version;
import org.terasology.naming.exception.VersionParseException;
import org.terasology.web.version.VersionInfo;
import org.terasology.web.model.ModuleListModel;
import org.terasology.web.model.jenkins.Job;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import com.google.gson.stream.JsonWriter;

/**
 * TODO Type description
 */
@Path("/modules/")
public class ModuleServlet {

    private static final Logger logger = LoggerFactory.getLogger(ModuleServlet.class);

    private final ModuleListModel model;

    private final ModuleMetadataJsonAdapter metadataWriter;

    /**
     * Sorts modules descending by version - id is ignored
     */
    private final Comparator<Module> versionComparator = (m1, m2) -> m2.getVersion().compareTo(m1.getVersion());

    public ModuleServlet(ModuleListModel model) {
        this.model = model;
        this.metadataWriter = new ModuleMetadataJsonAdapter();
        for (RemoteModuleExtension ext : RemoteModuleExtension.values()) {
            metadataWriter.registerExtension(ext.getKey(), ext.getValueType());
        }
    }

    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public Response list() {
        logger.info("Requested module list as json");

        StreamingOutput stream = os -> {
            List<Name> sortedModuleIds = new ArrayList<>(model.getModuleIds());
            sortedModuleIds.sort(null);
            try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
                writer.beginArray();
                writer.setIndent("  "); // enable pretty printing
                for (Name name : sortedModuleIds) {
                    for (Module module : model.getModuleVersions(name)) {
                        ModuleMetadata meta = module.getMetadata();
                        metadataWriter.write(meta, writer);
                    }
                }
                writer.endArray();
            }
        };
        return Response.ok(stream).build();
    }

    @GET
    @Path("show")
    @Produces(MediaType.TEXT_HTML)
    public Viewable show() {
        logger.info("Requested module list as HTML");

        Set<Name> names = model.getModuleIds();

        // the key needs to be string, so that FreeMarker can use it for lookups
        Multimap<String, Module> map = TreeMultimap.create(String.CASE_INSENSITIVE_ORDER, versionComparator);

        for (Name name : names) {
            map.putAll(name.toString(), model.getModuleVersions(name));
        }

        ImmutableMap<Object, Object> dataModel = ImmutableMap.builder().put("items", map.asMap())
                .put("version", VersionInfo.getVersion()).build();
        return new Viewable("/module-list.ftl", dataModel);
    }

    @GET
    @Path("list/latest")
    @Produces(MediaType.APPLICATION_JSON)
    public Response listLatest() {
        logger.info("Requested lastest info as json");

        StreamingOutput stream = os -> {
            List<Name> sortedModuleIds = new ArrayList<>(model.getModuleIds());
            sortedModuleIds.sort(null);
            try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
                writer.beginArray();
                writer.setIndent("  "); // enable pretty printing
                for (Name name : sortedModuleIds) {
                    Module module = model.getLatestModuleVersion(name);
                    ModuleMetadata meta = module.getMetadata();
                    metadataWriter.write(meta, writer);
                }
                writer.endArray();
            }
        };
        return Response.ok(stream).build();
    }

    @GET
    @Path("list/{module}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response listModule(@PathParam("module") String moduleName) {
        logger.info("Requested module versions as json");

        Name name = new Name(moduleName);

        StreamingOutput stream = os -> {
            try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
                writer.beginArray();
                writer.setIndent("  "); // enable pretty printing
                for (Module module : model.getModuleVersions(name)) {
                    ModuleMetadata meta = module.getMetadata();
                    metadataWriter.write(meta, writer);
                }
                writer.endArray();
            }
        };
        return Response.ok(stream).build();
    }

    @GET
    @Path("show/{module}")
    @Produces(MediaType.TEXT_HTML)
    public Viewable showModule(@PathParam("module") String module) {
        logger.info("Requested module versions as HTML");

        Name name = new Name(module);

        List<Module> sortedList = new ArrayList<>(model.getModuleVersions(name));
        sortedList.sort(versionComparator);

        Map<String, Collection<Module>> map = Collections.singletonMap(module, sortedList);

        ImmutableMap<Object, Object> dataModel = ImmutableMap.builder().put("items", map).put("moduleId", module)
                .put("version", VersionInfo.getVersion()).build();
        return new Viewable("/module-list.ftl", dataModel);
    }

    @GET
    @Path("list/{module}/latest")
    @Produces(MediaType.TEXT_HTML)
    public Response listModuleLatest(@Context UriInfo uriInfo, @PathParam("module") String module) {
        logger.info("Requested lastest module info as HTML");
        int pathLen = uriInfo.getPath().length();
        String path = uriInfo.getPath().substring(0, pathLen - "latest".length());
        Module latest = model.getLatestModuleVersion(new Name(module));
        if (latest == null) {
            return Response.status(Status.NOT_FOUND).build();
        }
        String ver = latest.getVersion().toString();
        URI redirect = URI.create(uriInfo.getBaseUri() + path + ver);
        return Response.temporaryRedirect(redirect).build();
    }

    @GET
    @Path("list/{module}/{version}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response listModuleVersion(@PathParam("module") String moduleName,
            @PathParam("version") String versionStr) {
        logger.info("Requested single module info as json");

        try {
            Version version = new Version(versionStr);
            Module module = model.getModule(new Name(moduleName), version);
            if (module == null) {
                return Response.status(Status.NOT_FOUND).build();
            }

            ModuleMetadata meta = module.getMetadata();

            StreamingOutput stream = os -> {
                try (OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
                    metadataWriter.write(meta, writer);
                }
            };
            return Response.ok(stream).build();
        } catch (VersionParseException e) {
            logger.warn("Invalid version for module '{}' specified: {}", moduleName, versionStr);
            return Response.status(Status.NOT_FOUND).build();
        }
    }

    @GET
    @Path("show/{module}/latest")
    @Produces(MediaType.TEXT_HTML)
    public Response showModuleLatest(@Context UriInfo uriInfo, @PathParam("module") String module) {
        logger.info("Requested lastest module info as HTML");
        int pathLen = uriInfo.getPath().length();
        String path = uriInfo.getPath().substring(0, pathLen - "latest".length());
        Module latest = model.getLatestModuleVersion(new Name(module));
        if (latest == null) {
            return Response.status(Status.NOT_FOUND).build();
        }
        String ver = latest.getVersion().toString();
        URI redirect = URI.create(uriInfo.getBaseUri() + path + ver);
        return Response.temporaryRedirect(redirect).build();
    }

    @GET
    @Path("show/{module}/{version}")
    @Produces(MediaType.TEXT_HTML)
    public Response showModuleVersion(@PathParam("module") String module, @PathParam("version") String version) {
        logger.info("Requested module info as HTML");

        try {
            Name moduleName = new Name(module);
            Version modVersion = new Version(version);
            Module mod = model.getModule(moduleName, modVersion);
            if (mod == null) {
                logger.warn("No entry for module '{}' found", module);
                return Response.status(Status.NOT_FOUND).build();
            }
            ModuleMetadata meta = mod.getMetadata();

            Set<Module> deps = model.resolve(moduleName, modVersion);

            ImmutableMap<Object, Object> dataModel = ImmutableMap.builder().put("meta", meta)
                    .put("updated", RemoteModuleExtension.getLastUpdated(meta))
                    .put("downloadUrl", RemoteModuleExtension.getDownloadUrl(meta))
                    .put("downloadSize", RemoteModuleExtension.getArtifactSize(meta) / 1024)
                    .put("dependencies", deps).put("version", VersionInfo.getVersion()).build();
            return Response.ok(new Viewable("/module-info.ftl", dataModel)).build();
        } catch (VersionParseException e) {
            logger.warn("Invalid version for module '{}' specified: {}", module, version);
            return Response.status(Status.NOT_FOUND).build();
        }
    }

    @POST
    @Path("update")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response updateModulePost(Job jobState) {
        String job = jobState.getName();

        logger.info("Requested module update for {}", job);

        model.updateModule(new Name(job));

        return Response.ok().build();
    }

    @POST
    @Path("update-all")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response updateAllModulesPost() {

        logger.info("Requested complete module update");

        new Thread(model::updateAllModules).start();

        return Response.ok().build();
    }
}