org.apache.zeppelin.kylin.KylinInterpreter.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.zeppelin.kylin.KylinInterpreter.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.zeppelin.kylin;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterPropertyBuilder;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Kylin interpreter for Zeppelin. (http://kylin.io)
 */
public class KylinInterpreter extends Interpreter {
    Logger logger = LoggerFactory.getLogger(KylinInterpreter.class);

    static final String KYLIN_QUERY_API_URL = "kylin.api.url";
    static final String KYLIN_USERNAME = "kylin.api.user";
    static final String KYLIN_PASSWORD = "kylin.api.password";
    static final String KYLIN_QUERY_PROJECT = "kylin.query.project";
    static final String KYLIN_QUERY_OFFSET = "kylin.query.offset";
    static final String KYLIN_QUERY_LIMIT = "kylin.query.limit";
    static final String KYLIN_QUERY_ACCEPT_PARTIAL = "kylin.query.ispartial";
    static final Pattern KYLIN_TABLE_FORMAT_REGEX_LABEL = Pattern.compile("\"label\":\"(.*?)\"");
    static final Pattern KYLIN_TABLE_FORMAT_REGEX = Pattern.compile("\"results\":\\[\\[\"(.*?)\"]]");

    static {
        Interpreter.register("kylin", "kylin", KylinInterpreter.class.getName(),
                new InterpreterPropertyBuilder().add(KYLIN_USERNAME, "ADMIN", "username for kylin user")
                        .add(KYLIN_PASSWORD, "KYLIN", "password for kylin user")
                        .add(KYLIN_QUERY_API_URL, "http://<host>:<port>/kylin/api/query", "Kylin API.")
                        .add(KYLIN_QUERY_PROJECT, "default", "kylin project name")
                        .add(KYLIN_QUERY_OFFSET, "0", "kylin query offset")
                        .add(KYLIN_QUERY_LIMIT, "5000", "kylin query limit")
                        .add(KYLIN_QUERY_ACCEPT_PARTIAL, "true", "The kylin query partial flag").build());
    }

    public KylinInterpreter(Properties property) {
        super(property);
    }

    @Override
    public void open() {

    }

    @Override
    public void close() {

    }

    @Override
    public InterpreterResult interpret(String st, InterpreterContext context) {
        try {
            return executeQuery(st);
        } catch (IOException e) {
            logger.error("failed to query data in kylin ", e);
            return new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage());
        }
    }

    @Override
    public void cancel(InterpreterContext context) {

    }

    @Override
    public FormType getFormType() {
        return FormType.SIMPLE;
    }

    @Override
    public int getProgress(InterpreterContext context) {
        return 0;
    }

    @Override
    public List<String> completion(String buf, int cursor) {
        return null;
    }

    public HttpResponse prepareRequest(String sql) throws IOException {
        String KYLIN_PROJECT = getProperty(KYLIN_QUERY_PROJECT);
        logger.info("project:" + KYLIN_PROJECT);
        logger.info("sql:" + sql);
        logger.info("acceptPartial:" + getProperty(KYLIN_QUERY_ACCEPT_PARTIAL));
        logger.info("limit:" + getProperty(KYLIN_QUERY_LIMIT));
        logger.info("offset:" + getProperty(KYLIN_QUERY_OFFSET));
        byte[] encodeBytes = Base64.encodeBase64(
                new String(getProperty(KYLIN_USERNAME) + ":" + getProperty(KYLIN_PASSWORD)).getBytes("UTF-8"));

        String postContent = new String("{\"project\":" + "\"" + KYLIN_PROJECT + "\"" + "," + "\"sql\":" + "\""
                + sql + "\"" + "," + "\"acceptPartial\":" + "\"" + getProperty(KYLIN_QUERY_ACCEPT_PARTIAL) + "\""
                + "," + "\"offset\":" + "\"" + getProperty(KYLIN_QUERY_OFFSET) + "\"" + "," + "\"limit\":" + "\""
                + getProperty(KYLIN_QUERY_LIMIT) + "\"" + "}");
        logger.info("post:" + postContent);
        postContent = postContent.replaceAll("[\u0000-\u001f]", " ");
        StringEntity entity = new StringEntity(postContent, "UTF-8");
        entity.setContentType("application/json; charset=UTF-8");

        logger.info("post url:" + getProperty(KYLIN_QUERY_API_URL));

        HttpPost postRequest = new HttpPost(getProperty(KYLIN_QUERY_API_URL));
        postRequest.setEntity(entity);
        postRequest.addHeader("Authorization", "Basic " + new String(encodeBytes));
        postRequest.addHeader("Accept-Encoding", "UTF-8");

        HttpClient httpClient = HttpClientBuilder.create().build();
        return httpClient.execute(postRequest);
    }

    private InterpreterResult executeQuery(String sql) throws IOException {

        HttpResponse response = prepareRequest(sql);

        if (response.getStatusLine().getStatusCode() != 200) {
            logger.error("failed to execute query: " + response.getEntity().getContent().toString());
            return new InterpreterResult(InterpreterResult.Code.ERROR,
                    "Failed : HTTP error code " + response.getStatusLine().getStatusCode());
        }

        BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));
        StringBuilder sb = new StringBuilder();

        String output;
        logger.info("Output from Server .... \n");
        while ((output = br.readLine()) != null) {
            logger.info(output);
            sb.append(output).append('\n');
        }
        InterpreterResult rett = new InterpreterResult(InterpreterResult.Code.SUCCESS, formatResult(sb.toString()));
        return rett;
    }

    private String formatResult(String msg) {
        StringBuilder res = new StringBuilder("%table ");

        Matcher ml = KYLIN_TABLE_FORMAT_REGEX_LABEL.matcher(msg);
        while (!ml.hitEnd() && ml.find()) {
            res.append(ml.group(1) + " \t");
        }
        res.append(" \n");

        Matcher mr = KYLIN_TABLE_FORMAT_REGEX.matcher(msg);
        String table = null;
        while (!mr.hitEnd() && mr.find()) {
            table = mr.group(1);
        }

        String[] row = table.split("\"],\\[\"");
        for (int i = 0; i < row.length; i++) {
            String[] col = row[i].split("\",\"");
            for (int j = 0; j < col.length; j++) {
                res.append(col[j] + " \t");
            }
            res.append(" \n");
        }
        return res.toString();
    }

}