All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scouterx.webapp.layer.controller.XLogDataController Maven / Gradle / Ivy

There is a newer version: 2.20.0
Show newest version
/*
 *  Copyright 2015 the original author or authors.
 *  @https://github.com/scouter-project/scouter
 *
 *  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 scouterx.webapp.layer.controller;

import com.fasterxml.jackson.core.JsonGenerator;
import io.swagger.annotations.Api;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import scouter.lang.constants.ParamConstant;
import scouter.lang.pack.MapPack;
import scouter.lang.pack.Pack;
import scouter.lang.pack.PackEnum;
import scouter.lang.pack.XLogPack;
import scouter.util.IntSet;
import scouterx.webapp.framework.cache.XLogLoopCache;
import scouterx.webapp.framework.client.model.TextModel;
import scouterx.webapp.framework.client.net.INetReader;
import scouterx.webapp.framework.client.server.Server;
import scouterx.webapp.framework.client.server.ServerManager;
import scouterx.webapp.layer.service.XLogService;
import scouterx.webapp.model.XLogData;
import scouterx.webapp.model.XLogPackWrapper;
import scouterx.webapp.request.GxidXLogRequest;
import scouterx.webapp.request.MultiXLogRequest;
import scouterx.webapp.request.PageableXLogRequest;
import scouterx.webapp.request.RealTimeXLogDataRequest;
import scouterx.webapp.request.SearchXLogRequest;
import scouterx.webapp.request.SingleXLogRequest;
import scouterx.webapp.view.CommonResultView;
import scouterx.webapp.view.PageableXLogView;

import javax.inject.Singleton;
import javax.validation.Valid;
import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.text.ParseException;
import java.util.List;
import java.util.function.Consumer;

/**
 * This controller provides apis for end users who want to get XLog data using http call.
 * @author Gun Lee ([email protected]) on 2017. 8. 29.
 */
@Path("/v1/xlog-data")
@Api("XLog data")
@Singleton
@Produces(MediaType.APPLICATION_JSON)
@Slf4j
public class XLogDataController {
    private final static long WAITING_DELAY_FOR_DICTIONARY_COMPLETE = 2000L;
    private final XLogService xLogService;

    public XLogDataController() {
        this.xLogService = new XLogService();
    }

    @Data
    private static class XLogCountBucket {
        int count;
        long loop;
        int index;

        private int getCount() {
            return count;
        }
        private void setCount(int count) {
            this.count = count;
        }
        private long getLoop() {
            return loop;
        }
        private void setLoop(long loop) {
            this.loop = loop;
        }
        private int getIndex() {
            return index;
        }
        private void setIndex(int index) {
            this.index = index;
        }
    }

    /**
     * get current xlog data created after the last searched.
     * uri : /xlog-data/realTime/0/100?objHashes=10001,10002 or ?objHashes=[10001,100002]
     *
     * @return
     */
    @GET
    @Path("/realTime/{offset1}/{offset2}")
    public Response streamRealTimeXLog(@BeanParam @Valid final RealTimeXLogDataRequest xLogRequest) {
        Server server = ServerManager.getInstance().getServerIfNullDefault(xLogRequest.getServerId());
        IntSet objHashSet = new IntSet();
        for (Integer objHash : xLogRequest.getObjHashes()) {
            objHashSet.add(objHash);
        }

        Consumer realTimeXLogHandlerConsumer = jsonGenerator -> {
            try {
                XLogCountBucket countBucket = new XLogCountBucket();
                countBucket.setLoop(xLogRequest.getXLogLoop());
                countBucket.setIndex(xLogRequest.getXLogIndex());

                jsonGenerator.writeArrayFieldStart("xlogs");

                XLogLoopCache.getOf(server.getId()).getAndHandleRealTimeXLog(
                        objHashSet, xLogRequest.getXLogLoop(), xLogRequest.getXLogIndex(), 10000,
                        WAITING_DELAY_FOR_DICTIONARY_COMPLETE, getRealTimeXLogReader(jsonGenerator, countBucket, server));

                jsonGenerator.writeEndArray();
                jsonGenerator.writeNumberField("offset1", countBucket.getLoop());
                jsonGenerator.writeNumberField("offset2", countBucket.getIndex());
                jsonGenerator.writeNumberField("count", countBucket.getCount());

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };

        TextModel.startScope();
        StreamingOutput streamingOutput = outputStream ->
                CommonResultView.jsonStream(outputStream, realTimeXLogHandlerConsumer);

        return Response.ok().entity(streamingOutput).type(MediaType.APPLICATION_JSON).build();
    }

    /**
     * request xlog data within given time range
     * uri : /xlog-data/{yyyymmdd}?startTime=... @see {@link PageableXLogRequest}
     *
     * @param xLogRequest
     * @return PageableXLogView @see {@link PageableXLogView}
     */
    @GET
    @Path("/{yyyymmdd}")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response streamPageableXLog(@Valid @BeanParam PageableXLogRequest xLogRequest) throws ParseException {
        xLogRequest.validate();
        Server server = ServerManager.getInstance().getServerIfNullDefault(xLogRequest.getServerId());
        Consumer pageableXLogHandlerConsumer = jsonGenerator -> {
            try {
                jsonGenerator.writeArrayFieldStart("xlogs");
                xLogService.handlePageableXLog(xLogRequest, getPageableXLogReader(jsonGenerator, server.getId()));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };

        TextModel.startScope();
        StreamingOutput streamingOutput = outputStream ->
                CommonResultView.jsonStream(outputStream, pageableXLogHandlerConsumer);

        return Response.ok().entity(streamingOutput).type(MediaType.APPLICATION_JSON).build();
    }

    /**
     * request xlog by txid
     * uri : /{yyyymmdd}/{txid} @see {@link SingleXLogRequest}
     *
     * @param singleXlogRequest
     */
    @GET
    @Path("/{yyyymmdd}/{txid}")
    @Consumes(MediaType.APPLICATION_JSON)
    public CommonResultView retrieveSingleXLog(@Valid @BeanParam SingleXLogRequest singleXlogRequest) {
        singleXlogRequest.validate();
        XLogData xLogData = xLogService.retrieveSingleXLogData(singleXlogRequest);

        return CommonResultView.success(xLogData);
    }

    /**
     * request xlog by txid
     * uri : /{yyyymmdd}/multi @see {@link MultiXLogRequest}
     *
     * @param multiXLogRequest
     */
    @GET
    @Path("/{yyyymmdd}/multi/{txidList}")
    @Consumes(MediaType.APPLICATION_JSON)
    public CommonResultView> retrieveXLogDataListByTxids(@Valid @BeanParam MultiXLogRequest multiXLogRequest) {
        List xLogs = xLogService.retrieveXLogDataListByTxids(multiXLogRequest);

        return CommonResultView.success(xLogs);
    }

    /**
     * request xlogs by gxid
     * uri : /{yyyymmdd}/gxid/{gxid} @see {@link GxidXLogRequest}
     *
     * @param gxidRequest
     */
    @GET
    @Path("/{yyyymmdd}/gxid/{gxid}")
    @Consumes(MediaType.APPLICATION_JSON)
    public CommonResultView> retrieveXLogDataListByGxid(@Valid @BeanParam GxidXLogRequest gxidRequest) {
        gxidRequest.validate();
        List xLogs = xLogService.retrieveXLogDataListByGxid(gxidRequest);

        return CommonResultView.success(xLogs);
    }


    /**
     * request xlog data list with various condition 
     * uri : /xlog-data/search/{yyyymmdd}?startHms=... @see {@link SearchXLogRequest}
     *
     * @param xLogRequest
     */
    @GET
    @Path("/search/{yyyymmdd}")
    @Consumes(MediaType.APPLICATION_JSON)
    public CommonResultView searchXLog(@Valid @BeanParam SearchXLogRequest xLogRequest) throws ParseException {
        xLogRequest.validate();

        TextModel.startScope();
        List list = xLogService.searchXLogDataList(xLogRequest);
        TextModel.endScope();
        
        return CommonResultView.success(list);
    }

    /**
     * get INetReader to make streaming output from realtime xlogs.
     *
     * @param jsonGenerator - low-level streaming json generator
     * @param countBucket - to keep xlog count and last index
     * @param server - server (needs for retrieving dictionary text)
     * @return INetReader
     */
    private Consumer getRealTimeXLogReader(JsonGenerator jsonGenerator, XLogCountBucket countBucket, Server server) {
        return xLogPackWrapper -> {
            try {
                jsonGenerator.writeObject(XLogData.of(xLogPackWrapper.getPack(), server.getId()));
                countBucket.setCount(countBucket.getCount() + 1);
                countBucket.setLoop(xLogPackWrapper.getLoop());
                countBucket.setIndex(xLogPackWrapper.getIndex());

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };
    }

    /**
     * get INetReader to make streaming output from xlogs.
     *
     * @param jsonGenerator - low-level streaming json generator
     * @param serverId - serverId (needs for retrieving dictionary text)
     * @return INetReader
     */
    private INetReader getPageableXLogReader(JsonGenerator jsonGenerator, int serverId) {
        int[] countable = {0};

        return in -> {
            Pack p = in.readPack();
            if (p.getPackType() != PackEnum.MAP) { // XLogPack case
                XLogPack xLogPack = (XLogPack) p;
                jsonGenerator.writeObject(XLogData.of(xLogPack, serverId));
                countable[0]++;
            } else { // MapPack case (//meta data arrive followed by xlog pack)
                jsonGenerator.writeEndArray();

                MapPack metaPack = (MapPack) p;
                jsonGenerator.writeBooleanField("hasMore", metaPack.getBoolean(ParamConstant.XLOG_RESULT_HAS_MORE));
                jsonGenerator.writeNumberField("lastTxid", metaPack.getLong(ParamConstant.XLOG_RESULT_LAST_TXID));
                jsonGenerator.writeNumberField("lastXLogTime", metaPack.getLong(ParamConstant.XLOG_RESULT_LAST_TIME));
                jsonGenerator.writeNumberField("count", countable[0]);
            }
        };
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy