com.navercorp.pinpoint.web.controller.ScatterChartController.java Source code

Java tutorial

Introduction

Here is the source code for com.navercorp.pinpoint.web.controller.ScatterChartController.java

Source

/*
 * Copyright 2014 NAVER Corp.
 *
 * 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 com.navercorp.pinpoint.web.controller;

import com.navercorp.pinpoint.common.server.bo.SpanBo;
import com.navercorp.pinpoint.common.util.DateUtils;
import com.navercorp.pinpoint.common.util.TransactionId;
import com.navercorp.pinpoint.common.util.TransactionIdComparator;
import com.navercorp.pinpoint.web.filter.Filter;
import com.navercorp.pinpoint.web.filter.FilterBuilder;
import com.navercorp.pinpoint.web.scatter.ScatterData;
import com.navercorp.pinpoint.web.service.FilteredMapService;
import com.navercorp.pinpoint.web.service.ScatterChartService;
import com.navercorp.pinpoint.web.util.LimitUtils;
import com.navercorp.pinpoint.web.view.ServerTime;
import com.navercorp.pinpoint.web.view.TransactionMetaDataViewModel;
import com.navercorp.pinpoint.web.vo.LimitedScanResult;
import com.navercorp.pinpoint.web.vo.Range;
import com.navercorp.pinpoint.web.vo.TransactionMetadataQuery;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;
import java.util.Map;

/**
 * @author netspider
 * @author emeroad
 * @author jaehong.kim
 */
@Controller
public class ScatterChartController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ScatterChartService scatter;

    @Autowired
    private FilteredMapService flow;

    @Autowired
    private FilterBuilder<SpanBo> filterBuilder;

    private static final String PREFIX_TRANSACTION_ID = "I";
    private static final String PREFIX_TIME = "T";
    private static final String PREFIX_RESPONSE_TIME = "R";

    @Deprecated
    @RequestMapping(value = "/scatterpopup", method = RequestMethod.GET)
    public String scatterPopup(Model model, @RequestParam("application") String applicationName,
            @RequestParam("from") long from, @RequestParam("to") long to, @RequestParam("period") long period,
            @RequestParam("usePeriod") boolean usePeriod,
            @RequestParam(value = "filter", required = false) String filterText) {
        model.addAttribute("applicationName", applicationName);
        model.addAttribute("from", from);
        model.addAttribute("to", to);
        model.addAttribute("period", period);
        model.addAttribute("usePeriod", usePeriod);
        model.addAttribute("filter", filterText);
        return "scatterPopup";
    }

    /**
     * selected points from scatter chart data query
     *
     * @param requestParam
     * @return
     */
    @RequestMapping(value = "/transactionmetadata", method = RequestMethod.POST)
    @ResponseBody
    public TransactionMetaDataViewModel transactionmetadata(@RequestParam Map<String, String> requestParam) {
        TransactionMetaDataViewModel viewModel = new TransactionMetaDataViewModel();
        TransactionMetadataQuery query = parseSelectTransaction(requestParam);
        if (query.size() > 0) {
            List<SpanBo> metadata = scatter.selectTransactionMetadata(query);
            viewModel.setSpanBoList(metadata);
        }

        return viewModel;
    }

    private TransactionMetadataQuery parseSelectTransaction(Map<String, String> requestParam) {
        final TransactionMetadataQuery query = new TransactionMetadataQuery();
        int index = 0;
        while (true) {
            final String transactionId = requestParam.get(PREFIX_TRANSACTION_ID + index);
            final String time = requestParam.get(PREFIX_TIME + index);
            final String responseTime = requestParam.get(PREFIX_RESPONSE_TIME + index);

            if (transactionId == null || time == null || responseTime == null) {
                break;
            }

            query.addQueryCondition(transactionId, Long.parseLong(time), Integer.parseInt(responseTime));
            index++;
        }
        logger.debug("query:{}", query);
        return query;
    }

    /**
     * @param applicationName
     * @param from
     * @param to
     * @param limit           max number of data return. if the requested data exceed this limit, we need additional calls to
     *                        fetch the rest of the data
     * @return
     */
    @RequestMapping(value = "/getScatterData", method = RequestMethod.GET)
    public ModelAndView getScatterData(@RequestParam("application") String applicationName,
            @RequestParam("from") long from, @RequestParam("to") long to,
            @RequestParam("xGroupUnit") int xGroupUnit, @RequestParam("yGroupUnit") int yGroupUnit,
            @RequestParam("limit") int limit,
            @RequestParam(value = "backwardDirection", required = false, defaultValue = "true") boolean backwardDirection,
            @RequestParam(value = "filter", required = false) String filterText,
            @RequestParam(value = "_callback", required = false) String jsonpCallback,
            @RequestParam(value = "v", required = false, defaultValue = "1") int version) {
        if (xGroupUnit <= 0) {
            throw new IllegalArgumentException("xGroupUnit(" + xGroupUnit + ") must be positive number");
        }
        if (yGroupUnit < 0) {
            throw new IllegalArgumentException("yGroupUnit(" + yGroupUnit + ") may not be negative number");
        }

        limit = LimitUtils.checkRange(limit);

        StopWatch watch = new StopWatch();
        watch.start("getScatterData");

        // TODO range check verification exception occurs. "from" is bigger than "to"
        final Range range = Range.createUncheckedRange(from, to);
        logger.debug(
                "fetch scatter data. RANGE={}, X-Group-Unit:{}, Y-Group-Unit:{}, LIMIT={}, BACKWARD_DIRECTION:{}, FILTER:{}",
                range, xGroupUnit, yGroupUnit, limit, backwardDirection, filterText);

        ModelAndView mv = null;
        if (StringUtils.isEmpty(filterText)) {
            mv = selectScatterData(applicationName, range, xGroupUnit, Math.max(yGroupUnit, 1), limit,
                    backwardDirection, version);
        } else {
            mv = selectFilterScatterData(applicationName, range, xGroupUnit, Math.max(yGroupUnit, 1), limit,
                    backwardDirection, filterText, version);
        }

        if (jsonpCallback == null) {
            mv.setViewName("jsonView");
        } else {
            mv.setViewName("jsonpView");
        }

        watch.stop();

        logger.info("Fetch scatterData time : {}ms", watch.getLastTaskTimeMillis());

        return mv;
    }

    private ModelAndView selectScatterData(String applicationName, Range range, int xGroupUnit, int yGroupUnit,
            int limit, boolean backwardDirection, int version) {
        ModelAndView mv = null;
        if (version == 1) {
            final ScatterData scatterData = scatter.selectScatterData(applicationName, range, xGroupUnit,
                    yGroupUnit, limit, backwardDirection);
            boolean requestComplete = scatterData.getDotSize() < limit;

            mv = createScatterDataV1(scatterData, requestComplete);
        } else {
            mv = new ModelAndView();
        }

        mv.addObject("currentServerTime", new ServerTime().getCurrentServerTime());
        mv.addObject("from", range.getFrom());
        mv.addObject("to", range.getTo());
        return mv;
    }

    private ModelAndView selectFilterScatterData(String applicationName, Range range, int xGroupUnit,
            int yGroupUnit, int limit, boolean backwardDirection, String filterText, int version) {
        final LimitedScanResult<List<TransactionId>> limitedScanResult = flow
                .selectTraceIdsFromApplicationTraceIndex(applicationName, range, limit, backwardDirection);

        final List<TransactionId> transactionIdList = limitedScanResult.getScanData();
        logger.trace("submitted transactionId count={}", transactionIdList.size());

        boolean requestComplete = transactionIdList.size() < limit;

        transactionIdList.sort(TransactionIdComparator.INSTANCE);
        Filter<SpanBo> filter = filterBuilder.build(filterText);

        ModelAndView mv;
        if (version == 1) {
            ScatterData scatterData = scatter.selectScatterData(transactionIdList, applicationName, range,
                    xGroupUnit, yGroupUnit, filter);
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "getScatterData range scan(limited:{}, backwardDirection:{}) from ~ to:{} ~ {}, limited:{}, filterDataSize:{}",
                        limit, backwardDirection, DateUtils.longToDateStr(range.getFrom()),
                        DateUtils.longToDateStr(range.getTo()),
                        DateUtils.longToDateStr(limitedScanResult.getLimitedTime()), transactionIdList.size());
            }

            mv = createScatterDataV1(scatterData, requestComplete);
        } else {
            mv = new ModelAndView();
        }

        mv.addObject("currentServerTime", new ServerTime().getCurrentServerTime());
        mv.addObject("from", range.getFrom());
        mv.addObject("to", range.getTo());
        return mv;
    }

    private ModelAndView createScatterDataV1(ScatterData scatterData, boolean complete) {
        ModelAndView mv = new ModelAndView();

        mv.addObject("resultFrom", scatterData.getOldestAcceptedTime());
        mv.addObject("resultTo", scatterData.getLatestAcceptedTime());

        mv.addObject("complete", complete);
        mv.addObject("scatter", scatterData);

        return mv;
    }

}