org.psjava.site.PsjavaSiteController.java Source code

Java tutorial

Introduction

Here is the source code for org.psjava.site.PsjavaSiteController.java

Source

package org.psjava.site;

import japa.parser.JavaParser;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.JavadocComment;
import japa.parser.ast.stmt.BlockStmt;
import japa.parser.ast.visitor.VoidVisitorAdapter;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import models.Item;

import org.json.JSONArray;
import org.psjava.ds.array.Array;
import org.psjava.ds.array.DynamicArray;
import org.psjava.site.util.HttpUtil;
import org.psjava.site.util.StringUtil;
import org.psjava.site.util.Util;
import org.psjava.util.AssertStatus;
import org.psjava.util.DataKeeper;
import org.psjava.util.Pair;
import org.psjava.util.Triple;
import org.psjava.util.ZeroTo;

import play.libs.F.Function;
import play.libs.F.Promise;
import play.libs.WS.Response;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.detail;
import views.html.index;

public class PsjavaSiteController extends Controller {

    private static final HashMap<String, String> EMPTY_PARAM = new HashMap<String, String>();
    private static final String ALGO_LIST_URL = constructApiUrl("src/test/java/org/psjava/example/algo");
    private static final String DS_LIST_URL = constructApiUrl("src/test/java/org/psjava/example/ds");
    private static final String EXAMPLE_PATH = "src/test/java/org/psjava/example";
    private static final String REF_NAME = "master";
    private static final String GITHUB_RAW_ROOT = "https://raw.github.com/psjava/psjava/" + REF_NAME;
    private static final String GITHUB_PAGE_ROOT = "https://github.com/psjava/psjava/blob/" + REF_NAME;
    private static final String EXAMPLE_FILE_SUFFIX = "Example.java";

    @SuppressWarnings("unchecked")
    public static Promise<Result> index() {
        Promise<Response> pom = createPomFileReceivePromise();
        Promise<Response> ds = HttpUtil.createCacheableUrlFetchPromise(DS_LIST_URL, createRefParam());
        Promise<Response> algo = HttpUtil.createCacheableUrlFetchPromise(ALGO_LIST_URL, createRefParam());
        return Promise.sequence(pom, ds, algo).map(new Function<List<Response>, Result>() {
            @Override
            public Result apply(List<Response> list) throws Throwable {
                String pomFileText = list.get(0).getBody();
                String version = extractVersion(pomFileText);
                List<Item> ds = extractItems(list.get(1));
                List<Item> algo = extractItems(list.get(2));
                return ok(index.render(version, ds, algo));
            }
        });
    }

    private static Promise<Response> createPomFileReceivePromise() {
        return HttpUtil.createCacheableUrlFetchPromise(GITHUB_RAW_ROOT + "/pom.xml", EMPTY_PARAM);
    }

    private static String constructApiUrl(String dirPath) {
        return "https://api.github.com/repos/psjava/psjava/contents/" + dirPath;
    }

    private static String extractVersion(String pomFileText) {
        String start = "<version>";
        int s = pomFileText.indexOf(start);
        int e = pomFileText.indexOf("</version>");
        return pomFileText.substring(s + "<version>".length(), e);
    }

    public static Promise<Result> showDs(String id) {
        return showDetail("ds", id);
    }

    public static Promise<Result> showAlgo(String id) {
        return showDetail("algo", id);
    }

    public static Result clearCache() {
        HttpUtil.clearCached();
        return redirect("/");
    }

    @SuppressWarnings("unchecked")
    private static Promise<Result> showDetail(String categoryx, final String id) {
        String exampleUrl = GITHUB_RAW_ROOT + "/" + EXAMPLE_PATH + "/" + categoryx + "/" + id.replace("_", "")
                + EXAMPLE_FILE_SUFFIX;
        Promise<Response> pom = createPomFileReceivePromise();
        Promise<Response> example = HttpUtil.createCacheableUrlFetchPromise(exampleUrl, EMPTY_PARAM);
        Promise<Response> dsList = HttpUtil.createCacheableUrlFetchPromise(DS_LIST_URL, createRefParam());
        Promise<Response> algoList = HttpUtil.createCacheableUrlFetchPromise(ALGO_LIST_URL, createRefParam());
        return Promise.sequence(pom, example, dsList, algoList).map(new Function<List<Response>, Result>() {
            @Override
            public Result apply(List<Response> list) throws Throwable {
                String pomFileText = list.get(0).getBody();
                final String content = list.get(1).getBody();
                List<Item> ds = extractItems(list.get(2));
                List<Item> algo = extractItems(list.get(3));

                CompilationUnit cu = JavaParser.parse(new ByteArrayInputStream(content.getBytes("UTF-8")), "UTF-8");
                final DynamicArray<String> implementationSimpleClassName = DynamicArray.create();
                final DynamicArray<String> seeAlsoClassName = DynamicArray.create();
                new VoidVisitorAdapter<Object>() {
                    @Override
                    public void visit(ClassOrInterfaceDeclaration n, Object arg) {
                        JavadocComment docOrNull = n.getJavaDoc();
                        if (docOrNull == null)
                            return;
                        for (String line : StringUtil.toLines(docOrNull.getContent())) {
                            if (line.contains("@")) {
                                if (line.contains("@implementation"))
                                    implementationSimpleClassName
                                            .addToLast(extractSimpleClassNameFromTagLine(line));
                                else if (line.contains("@see"))
                                    seeAlsoClassName.addToLast(extractSimpleClassNameFromTagLine(line));
                                else
                                    throw new RuntimeException();
                            }
                        }
                    }
                }.visit(cu, null);
                final DataKeeper<String> exampleBody = new DataKeeper<String>("");
                new VoidVisitorAdapter<Object>() {
                    @Override
                    public void visit(BlockStmt stmt, Object arg1) {
                        String body = "";
                        Array<String> lines = StringUtil.toLines(content);
                        for (int i : ZeroTo.get(lines.size())) {
                            if (stmt.getBeginLine() <= i && i < stmt.getEndLine() - 1) {
                                String line = lines.get(i);
                                if (!line.trim().startsWith("Assert.assert")) {
                                    if (line.startsWith("\t\t"))
                                        body += line.substring(2) + "\n";
                                    else
                                        body += line + "\n";
                                }
                            }
                        }
                        AssertStatus.assertTrue(exampleBody.get().length() == 0);
                        exampleBody.set(body);
                    }
                }.visit(cu, null);
                AssertStatus.assertTrue(exampleBody.get().length() > 0);

                DynamicArray<Pair<String, String>> impls = DynamicArray.create();
                for (String s : implementationSimpleClassName) {
                    String className = getClassNameFromImport(content, s);
                    impls.addToLast(Pair.create(s, GITHUB_PAGE_ROOT + "/" + "src/main/java" + "/"
                            + className.replace('.', '/') + ".java"));
                }

                DynamicArray<Triple<String, String, String>> seeAlsos = DynamicArray.create();
                for (String s : seeAlsoClassName) {
                    String name = extractName(s + ".java");
                    Item found = null;
                    for (Item item : ds)
                        if (item.name.equals(name))
                            found = item;
                    if (found != null)
                        seeAlsos.addToLast(Triple.create(name, "ds", found.id));
                    Item found2 = null;
                    for (Item item : algo)
                        if (item.name.equals(name))
                            found2 = item;
                    if (found2 != null)
                        seeAlsos.addToLast(Triple.create(name, "algo", found2.id));
                }

                return ok(detail.render(extractVersion(pomFileText), getName(id), exampleBody.get().trim(),
                        Util.toList(impls), Util.toList(seeAlsos)));
            }
        });
    }

    private static Map<String, String> createRefParam() {
        Map<String, String> param = new HashMap<String, String>();
        param.put("ref", REF_NAME);
        return param;
    }

    private static String getName(String id) {
        return id.replace('_', ' ');
    }

    protected static String extractName(String fileName) {
        AssertStatus.assertTrue(fileName.endsWith(EXAMPLE_FILE_SUFFIX));
        String sub = fileName.substring(0, fileName.length() - EXAMPLE_FILE_SUFFIX.length());
        return getCamelResolved(sub);
    }

    public static String getCamelResolved(String name) {
        String r = "";
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if (i > 0 && Character.isUpperCase(c))
                r += " ";
            r += c;
        }
        return r;
    }

    private static String extractSimpleClassNameFromTagLine(String line) {
        String temp = line.substring(line.indexOf("{@link")).trim();
        temp = temp.replace("{@link", "").replace("}", "").trim();
        return temp;
    }

    private static ArrayList<Item> extractItems(Response gitHubResponse) {
        JSONArray dsJson = new JSONArray(gitHubResponse.getBody());
        ArrayList<Item> r = new ArrayList<Item>();
        for (int i : ZeroTo.get(dsJson.length())) {
            String name = extractName(dsJson.getJSONObject(i).getString("name"));
            String id = name.replace(' ', '_');
            r.add(new Item(id, name));
        }
        return r;
    }

    private static String getClassNameFromImport(String content, String s) {
        Array<String> lines = StringUtil.toLines(content);
        for (String line : lines)
            if (line.startsWith("import") && line.contains("." + s))
                return line.substring(line.indexOf(' '), line.indexOf(';')).trim();
        throw new RuntimeException("Cannot find class from import statement: " + s);
    }

    public static Promise<Result> license() {
        return HttpUtil.createCacheableUrlFetchPromise(GITHUB_RAW_ROOT + "/LICENSE", EMPTY_PARAM)
                .map(new Function<Response, Result>() {
                    @Override
                    public Result apply(Response arg0) throws Throwable {
                        return ok(views.html.license.render(arg0.getBody()));
                    }
                });
    }

}