com.jredrain.startup.AgentProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.jredrain.startup.AgentProcessor.java

Source

/**
 * Copyright 2016 benjobs
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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.jredrain.startup;

import com.alibaba.fastjson.JSON;
import com.jredrain.common.job.*;
import org.apache.commons.exec.*;
import org.apache.thrift.TException;
import com.jredrain.common.utils.*;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.slf4j.Logger;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Method;
import java.util.*;

import static com.jredrain.common.utils.CommonUtils.*;

/**
 * Created by benjo on 2016/3/25.
 */
public class AgentProcessor implements RedRain.Iface {

    private Logger logger = LoggerFactory.getLogger(AgentProcessor.class);

    private String password;

    private Integer agentPort;

    private Integer socketPort;

    private final String EXITCODE_KEY = "exitCode";

    private final String EXITCODE_SCRIPT = String.format(" \n echo %s:$?", EXITCODE_KEY);

    private final String REPLACE_REX = "%s:\\sline\\s[0-9]+:";

    private AgentMonitor agentMonitor;

    public AgentProcessor(String password, Integer agentPort) {
        this.password = password;
        this.agentPort = agentPort;
    }

    @Override
    public Response ping(Request request) throws TException {
        if (!this.password.equalsIgnoreCase(request.getPassword())) {
            return errorPasswordResponse(request);
        }
        return Response.response(request).setSuccess(true).setExitCode(RedRain.StatusCode.SUCCESS_EXIT.getValue())
                .end();
    }

    @Override
    public Response monitor(Request request) throws TException {
        RedRain.ConnType connType = RedRain.ConnType.getByName(request.getParams().get("connType"));
        Response response = Response.response(request);
        Map<String, String> map = new HashMap<String, String>(0);

        if (agentMonitor == null) {
            agentMonitor = new AgentMonitor();
        }

        switch (connType) {
        case CONN:
            if (CommonUtils.isEmpty(agentMonitor, socketPort) || agentMonitor.stoped()) {
                //?port
                this.socketPort = HttpUtils.freePort();
                try {
                    agentMonitor.start(socketPort);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            logger.debug("[redrain]:getMonitorPort @:{}", socketPort);
            map.put("port", this.socketPort.toString());
            response.setResult(map);
            return response;
        case PROXY:
            Monitor monitor = agentMonitor.monitor();
            map = serializableToMap(monitor);
            response.setResult(map);
            return response;
        default:
            return null;
        }
    }

    @Override
    public Response proxy(Request request) throws TException {
        String proxyHost = request.getParams().get("proxyHost");
        String proxyPort = request.getParams().get("proxyPort");
        String proxyAction = request.getParams().get("proxyAction");
        String proxyPassword = request.getParams().get("proxyPassword");

        //?....
        String proxyParams = request.getParams().get("proxyParams");
        Map<String, String> params = new HashMap<String, String>(0);
        if (CommonUtils.notEmpty(proxyParams)) {
            params = (Map<String, String>) JSON.parse(proxyParams);
        }

        Request proxyReq = Request
                .request(proxyHost, toInt(proxyPort), Action.findByName(proxyAction), proxyPassword)
                .setParams(params);

        logger.info("[redrain]proxy params:{}", proxyReq.toString());

        TTransport transport = null;
        /**
         * ping5,
         */
        if (proxyReq.getAction().equals(Action.PING)) {
            transport = new TSocket(proxyReq.getHostName(), proxyReq.getPort(), 1000 * 5);
        } else {
            transport = new TSocket(proxyReq.getHostName(), proxyReq.getPort());
        }
        TProtocol protocol = new TBinaryProtocol(transport);
        RedRain.Client client = new RedRain.Client(protocol);
        transport.open();

        Response response = null;
        for (Method method : client.getClass().getMethods()) {
            if (method.getName().equalsIgnoreCase(proxyReq.getAction().name())) {
                try {
                    response = (Response) method.invoke(client, proxyReq);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                break;
            }
        }
        transport.flush();
        transport.close();
        return response;
    }

    @Override
    public Response execute(final Request request) throws TException {
        if (!this.password.equalsIgnoreCase(request.getPassword())) {
            return errorPasswordResponse(request);
        }

        String command = request.getParams().get("command") + EXITCODE_SCRIPT;

        String pid = request.getParams().get("pid");
        //??
        Long timeout = CommonUtils.toLong(request.getParams().get("timeout"), 0L);

        boolean timeoutFlag = timeout > 0;

        logger.info("[redrain]:execute:{},pid:{}", command, pid);

        File shellFile = CommandUtils.createShellFile(command, pid);

        Integer exitValue;

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        final Response response = Response.response(request);

        final ExecuteWatchdog watchdog = new ExecuteWatchdog(Integer.MAX_VALUE);

        final Timer timer = new Timer();

        DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();

        try {
            CommandLine commandLine = CommandLine.parse("/bin/bash +x " + shellFile.getAbsolutePath());
            final DefaultExecutor executor = new DefaultExecutor();

            ExecuteStreamHandler stream = new PumpStreamHandler(outputStream, outputStream);
            executor.setStreamHandler(stream);
            response.setStartTime(new Date().getTime());
            //?0,shell
            executor.setExitValue(0);

            if (timeoutFlag) {
                //...
                executor.setWatchdog(watchdog);
                //
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        //,kill...
                        if (watchdog.isWatching()) {
                            /**
                             * watchdogdestroyProcesskill...
                             * watchdog.destroyProcess();
                             */
                            timer.cancel();
                            watchdog.stop();
                            //call  kill...
                            request.setAction(Action.KILL);
                            try {
                                kill(request);
                                response.setExitCode(RedRain.StatusCode.TIME_OUT.getValue());
                            } catch (TException e) {
                                e.printStackTrace();
                            }

                        }
                    }
                }, timeout * 60 * 1000);

                //
                resultHandler = new DefaultExecuteResultHandler() {
                    @Override
                    public void onProcessComplete(int exitValue) {
                        super.onProcessComplete(exitValue);
                        timer.cancel();
                    }

                    @Override
                    public void onProcessFailed(ExecuteException e) {
                        super.onProcessFailed(e);
                        timer.cancel();
                    }
                };
            }

            executor.execute(commandLine, resultHandler);

            resultHandler.waitFor();

        } catch (Exception e) {
            if (e instanceof ExecuteException) {
                exitValue = ((ExecuteException) e).getExitValue();
            } else {
                exitValue = RedRain.StatusCode.ERROR_EXEC.getValue();
            }
            if (RedRain.StatusCode.KILL.getValue().equals(exitValue)) {
                if (timeoutFlag) {
                    timer.cancel();
                    watchdog.stop();
                }
                logger.info("[redrain]:job has be killed!at pid :{}", request.getParams().get("pid"));
            } else {
                logger.info("[redrain]:job execute error:{}", e.getCause().getMessage());
            }
        } finally {

            exitValue = resultHandler.getExitValue();

            if (CommonUtils.notEmpty(outputStream.toByteArray())) {
                try {
                    outputStream.flush();
                    String text = outputStream.toString();
                    if (notEmpty(text)) {
                        try {
                            text = text.replaceAll(String.format(REPLACE_REX, shellFile.getAbsolutePath()), "");
                            response.setMessage(text.substring(0, text.lastIndexOf(EXITCODE_KEY)));
                            exitValue = Integer.parseInt(text
                                    .substring(text.lastIndexOf(EXITCODE_KEY) + EXITCODE_KEY.length() + 1).trim());
                        } catch (IndexOutOfBoundsException e) {
                            response.setMessage(text);
                        }
                    }
                    outputStream.close();
                } catch (Exception e) {
                    logger.error("[redrain]:error:{}", e);
                }
            }

            if (RedRain.StatusCode.TIME_OUT.getValue() == response.getExitCode()) {
                response.setSuccess(false).end();
            } else {
                response.setExitCode(exitValue)
                        .setSuccess(response.getExitCode() == RedRain.StatusCode.SUCCESS_EXIT.getValue()).end();
            }

            if (shellFile != null) {
                shellFile.delete();//
            }
        }
        logger.info("[redrain]:execute result:{}", response.toString());
        watchdog.stop();

        return response;
    }

    @Override
    public Response password(Request request) throws TException {
        if (!this.password.equalsIgnoreCase(request.getPassword())) {
            return errorPasswordResponse(request);
        }

        String newPassword = request.getParams().get("newPassword");
        Response response = Response.response(request);

        if (isEmpty(newPassword)) {
            return response.setSuccess(false).setExitCode(RedRain.StatusCode.SUCCESS_EXIT.getValue())
                    .setMessage("??").end();
        }
        this.password = newPassword.toLowerCase().trim();

        IOUtils.writeText(Globals.REDRAIN_PASSWORD_FILE, this.password, "UTF-8");

        return response.setSuccess(true).setExitCode(RedRain.StatusCode.SUCCESS_EXIT.getValue()).end();
    }

    @Override
    public Response kill(Request request) throws TException {

        if (!this.password.equalsIgnoreCase(request.getPassword())) {
            return errorPasswordResponse(request);
        }

        String pid = request.getParams().get("pid");
        logger.info("[redrain]:kill pid:{}", pid);

        Response response = Response.response(request);
        String text = CommandUtils.executeShell(Globals.REDRAIN_KILL_SHELL, pid, EXITCODE_SCRIPT);
        String message = "";
        Integer exitVal = 0;

        if (notEmpty(text)) {
            try {
                message = text.substring(0, text.lastIndexOf(EXITCODE_KEY));
                exitVal = Integer.parseInt(
                        text.substring(text.lastIndexOf(EXITCODE_KEY) + EXITCODE_KEY.length() + 1).trim());
            } catch (StringIndexOutOfBoundsException e) {
                message = text;
            }
        }

        response.setExitCode(
                RedRain.StatusCode.ERROR_EXIT.getValue().equals(exitVal) ? RedRain.StatusCode.ERROR_EXIT.getValue()
                        : RedRain.StatusCode.SUCCESS_EXIT.getValue())
                .setMessage(message).end();

        logger.info("[redrain]:kill result:{}" + response);
        return response;
    }

    private Response errorPasswordResponse(Request request) {
        return Response.response(request).setSuccess(false)
                .setExitCode(RedRain.StatusCode.ERROR_PASSWORD.getValue())
                .setMessage(RedRain.StatusCode.ERROR_PASSWORD.getDescription()).end();
    }

    private Map<String, String> serializableToMap(Object obj) {
        if (isEmpty(obj)) {
            return Collections.EMPTY_MAP;
        }

        Map<String, String> resultMap = new HashMap<String, String>(0);
        // 
        try {
            PropertyDescriptor[] pds = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors();
            for (int index = 0; pds.length > 1 && index < pds.length; index++) {
                if (Class.class == pds[index].getPropertyType() || pds[index].getReadMethod() == null) {
                    continue;
                }
                Object value = pds[index].getReadMethod().invoke(obj);
                if (notEmpty(value)) {
                    if (isPrototype(pds[index].getPropertyType())//java()
                            || pds[index].getPropertyType().isPrimitive()//
                            || ReflectUitls.isPrimitivePackageType(pds[index].getPropertyType())
                            || pds[index].getPropertyType() == String.class) {

                        resultMap.put(pds[index].getName(), value.toString());

                    } else {
                        resultMap.put(pds[index].getName(), JSON.toJSONString(value));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

}