configurator.Configurator.java Source code

Java tutorial

Introduction

Here is the source code for configurator.Configurator.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package configurator;

import ipcalc.IPv4;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.net.telnet.TelnetClient;

/**
 *
 * @author rs
 */
public class Configurator {

    static Settings mainProperites = new Settings("configurator.conf");
    private static final Logger LOG = Logger.getLogger(Snmp.class.getName());

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws FileNotFoundException, IOException {
        //worktest:
        String commandList = "config ports 1 state enable\nconfig ports 3 state disable";
        AuthenticationData authData = new AuthenticationData("admin", "admin", "public", commandList);
        List<String> switchList = Arrays.asList("D-Link DES-1228/ME Metro Ethernet Switch", "D'link DES-3200");
        Configurator cf = new Configurator();
        cf.telnetWork("192.168.0.13", authData, switchList);
    }

    /**
     * The main method for telnet configuring the network devices. Prepare data
     * and create thread for each device
     *
     * @param ipText - List of ip ranges, subnets and single ip
     * @param authData - authorization data for work on devices
     * @param models list of models for telnet configure
     */
    void telnetWork(String ipText, AuthenticationData authData, List<String> models) {
        try {
            List<String> ipList = parseIp(ipText);
            ExecutorService exec = Executors.newCachedThreadPool();
            ipList.forEach((ip) -> {
                Snmp snmp = new Snmp(authData.getCommunity());
                String modelOid = mainProperites.getProperty("Identifier_Oid");
                String model = snmp.get(ip, modelOid).trim();
                if (models.contains(model)) {
                    try {
                        String modelAddress = getAddressByModelName(model);
                        if (modelAddress != null) {
                            exec.execute(new TelnetConfigureThread(ip, authData, modelAddress));
                        } else {
                            throw new FileNotFoundException();
                        }
                    } catch (FileNotFoundException ex) {
                        System.exit(0);
                    }
                } else {
                }
            });
            exec.shutdown();
        } catch (Exception e) {
            System.out.println(e);
            //ip address is incorrect
        }
    }

    /**
     * Method for getting address of configuration file of device by name
     *
     * @param name name of device;
     * @return address of configuration file;
     * @throws FileNotFoundException
     */
    String getAddressByModelName(String name) throws FileNotFoundException {
        Scanner switchReader = new Scanner(new FileReader("switchlist.txt"));
        String model;
        while (switchReader.hasNextLine()) {
            model = switchReader.nextLine();
            if (model.contains(name)) {
                return model.split("->")[1];
            }
        }
        return null;
    }

    /**
     * Thread for configuration single device
     */
    class TelnetConfigureThread implements Runnable {

        AuthenticationData authData;
        String ip;
        String modelConfigurationAddress;

        TelnetConfigureThread(String ip, AuthenticationData authData, String modelConfigurationAddress) {
            this.ip = ip;
            this.authData = authData;
            this.modelConfigurationAddress = modelConfigurationAddress;
        }

        @Override
        public void run() {
            Device device = new Device(modelConfigurationAddress);
            String report = device.telnetConfigure(authData.getLogin(), authData.getPassword(), ip,
                    authData.getCommandList());
            //if develop, later will be pipped out
            System.out.println(report);
        }
    }

    /**
     * Method for transform ip text to list of ip addresses. Check recording
     * method and select the method of conversion.
     *
     * @param ipText List of ip ranges, subnets and single ip
     * @return list of ip addresses
     */
    static List<String> parseIp(String ipText) {
        Scanner ipReader = new Scanner(ipText);
        List<String> ipList = new ArrayList<>();
        String ipLine;
        while (ipReader.hasNext()) {
            ipLine = ipReader.nextLine().trim();
            if (ipLine.contains("/")) {
                ipList.addAll(parseIpSubnet(ipLine));
            } else if (ipLine.contains("-")) {
                ipList.addAll(parseIpRange(ipLine));
            } else if (validateIP(ipLine)) {
                ipList.add(ipLine);
            } else {
                throw new NumberFormatException();
            }
        }
        return ipList;
    }

    /**
     * Method for transform ip range like "192.168.0.1-192.168.0.254" to list of
     * ips.
     *
     * @param ipRange String with first and last ip
     * @return List<String> with ip addresses
     */
    static List<String> parseIpRange(String ipRange) {
        List<String> ipList = new ArrayList<>();
        String ips[] = ipRange.split("-");

        if (!(validateIP(ips[0]) && validateIP(ips[1]))) {
            throw new NumberFormatException();
        }
        String[] ipOctets = ips[0].split("\\.");

        int[] ip = new int[4];
        for (int i = 0; i < 4; i++) {
            ip[i] = Integer.valueOf(ipOctets[i]);
        }

        ipList.add(ips[0]);
        while (!ips[0].equals(ips[1])) {
            ip[3]++;
            if (ip[3] == 0x100) {
                ip[3] = 0;
                ip[2]++;
            }
            if (ip[2] == 0x100) {
                ip[2] = 0;
                ip[1]++;
            }
            if (ip[1] > 254) {
                throw new NumberFormatException();
            }
            ips[0] = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3];
            ipList.add(ips[0]);
        }
        return ipList;
    }

    /**
     * Method for transform "ip/netmask" like "192.168.0.1/24" to list of ips.
     *
     * @param ipSubnet - String with ip and netmask
     * @return List<String> with ip addresses
     */
    static List<String> parseIpSubnet(String ipSubnet) {
        IPv4 ipv4 = new IPv4(ipSubnet);
        return ipv4.getAvailableIPs(ipv4.getNumberOfHosts());
    }

    /**
     * Method for validate ip address
     *
     * @param ip - ip address for validate
     * @return true if ip is falid, else false;
     */
    static boolean validateIP(String ip) {
        if (ip.startsWith("0")) {
            return false;
        }
        if (ip.isEmpty()) {
            return false;
        }
        return ip.matches("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    }

}

class Device {

    private final String usernamePrompt;
    private final String passwordPrompt;
    private final String commandPrompt;
    private final AnalysisMode analysisMode;
    private String answerValidation;
    private final Settings switchSettings;

    Device(String modelConfigurationFileAddress) {
        switchSettings = new Settings(
                "switches" + System.getProperty("file.separator") + modelConfigurationFileAddress);
        usernamePrompt = switchSettings.getProperty("Username_Prompt");
        passwordPrompt = switchSettings.getProperty("Password_Prompt");
        commandPrompt = switchSettings.getProperty("Command_Prompt");
        if (switchSettings.getProperty("Success_Mode").equals("Success")) {
            analysisMode = AnalysisMode.SUCCESS;
            answerValidation = switchSettings.getProperty("Answer_Validation");
        } else if (switchSettings.getProperty("Success_Mode").equals("Success")) {
            analysisMode = AnalysisMode.ERROR;
        } else {
            analysisMode = AnalysisMode.OFF;
        }
    }

    /**
     * Method for configuring device via telnet. Connect to device, authorizes,
     * and send to cli one by one line from command list, analyse every answer
     * and make report
     *
     * @param login username for authorization
     * @param password password for authorization
     * @param ip ip address of device
     * @param commandList command list for input on device
     * @return report of telnet configuring this device
     */
    String telnetConfigure(String login, String password, String ip, String commandList) {
        StringBuilder report = new StringBuilder("Configure: ");
        report.append(ip);
        try {
            Telnet telnet = new Telnet(login, password, ip);
            telnet.init(usernamePrompt, passwordPrompt, commandPrompt);
            Scanner commandReader = new Scanner(commandList);
            while (commandReader.hasNextLine()) {
                final String command = commandReader.nextLine();
                final String answer = telnet.sendCommand(command, commandPrompt);
                if (!(analysisMode == AnalysisMode.OFF)) {
                    if (!answerAnalysis(answer)) {
                        report.append("\n").append(command).append(":\n").append(answer);
                    }
                }
            }
            report.append("\n").append("Complete");
        } catch (IOException ex) {
            Logger.getLogger(Device.class.getName()).log(Level.SEVERE, null, ex);
            report.append("\nConnection problem");
        } catch (LoginFailedException ex) {
            report.append("\nAutentification failed: ").append(ip).append(" login: ").append(login);
        }
        return report.toString();
    }

    /**
     * Define the correctness of command input. If analysis mode by answer -
     * search word-confirmation on device answer. If analysis mode by error -
     * count value of line wrappings, if more than one - command not confirmed.
     *
     * @param answer - response from device for analysis
     * @return true if command is confirmed and false if command is not
     * confirmed.
     */
    private boolean answerAnalysis(String answer) {
        if (analysisMode == AnalysisMode.SUCCESS) {
            return answer.contains(answerValidation);
        } else {
            int count = 0;
            for (int i = 0; i < answer.length(); i++) {
                if (answer.charAt(i) == '\n') {
                    count++;
                }
            }
            return count <= 1;
        }
    }
}

class Telnet {

    TelnetClient telnet;
    private final InputStream in;
    private final PrintStream out;
    private final String login;
    private final String password;
    private final String solidMark;
    private final String ipMark;
    private static final Logger LOG = Logger.getLogger(Snmp.class.getName());
    private final String ip;

    Telnet(String login, String password, String ip) throws IOException {
        solidMark = Configurator.mainProperites.getProperty("solid_command_mark");
        ipMark = Configurator.mainProperites.getProperty("ip_command_mark");
        this.login = login;
        this.password = password;
        this.ip = ip;
        int port = Integer.valueOf(Configurator.mainProperites.getProperty("Telnet_Port"));
        telnet = new TelnetClient();
        telnet.connect(ip, port);
        in = telnet.getInputStream();
        out = new PrintStream(telnet.getOutputStream());
    }

    /**
     * To prepare divice for configuring via telnet
     *
     * @param userPrompt the combination of characters, which device output,
     * when be ready to take login
     * @param passwordPrompt the combination of characters, which device output,
     * when be ready to take password
     * @param commandPrompt the combination of characters, which device output,
     * when be ready to work via telnet
     * @throws IOException
     * @LoginFailedException login or password is incorrect
     */
    void init(String userPrompt, String passwordPrompt, String commandPrompt)
            throws IOException, LoginFailedException {
        readUntil(userPrompt);
        write(login);
        readUntil(passwordPrompt);
        write(password);
        String report = readUntil(commandPrompt, userPrompt);

        if (report.endsWith(userPrompt)) {
            //  ?
            //?  ? ? 
            telnet.disconnect();
            LOG.log(Level.INFO, "Autorization Failder {0} {1}", new Object[] { ip, login });
            throw new LoginFailedException(login, report);
        }
    }

    /**
     *  ?    ??.  ? ? ,
     * ?, ??  , ?  -   ??
     * , ? , ?  ??.
     *
     * @param command raw command
     * @param commandPrompt the combination of characters, which device output,
     * when be ready to take next command
     * @return response from device to entered command
     * @throws IOException
     */
    String sendCommand(String command, String commandPrompt) throws IOException {
        if (command.contains(solidMark)) {
            return passSolidCommand(command, commandPrompt);
        } else if (command.contains(ipMark)) {
            return passIpCommand(command, commandPrompt);
        } else {
            return passCommand(command, commandPrompt);
        }
    }

    /**
     * Finish the telnet session
     */
    void disconnect() throws IOException {
        LOG.log(Level.INFO, "Disconnect from  {0}", ip);
        telnet.disconnect();
    }

    /**
     * Send data to device. Pass data to output Stream and wait, when device to
     * be ready for next action
     *
     * @param command command for input on device
     * @param commandPrompt the combination of characters, which device output,
     * when be ready to take next command
     * @return response from device to entered command
     * @throws IOException
     */
    private String passCommand(String command, String commandPrompt) throws IOException {
        write(command);
        return readUntil(commandPrompt);
    }

    /**
     * Send range of solid commands to device. "Solid command" - command, which
     * contain one or several "solidSymbols". Solid command split up into
     * several regular commands, which pass to device without command prompt.
     * Usually solid command use, when first part of solid command is require
     * addiction data and change command prompt
     *
     * @param solidCommand solid command
     * @param commandPrompt the combination of characters, which device output,
     * when be ready to take next
     * @return response from device to entered command
     * @throws IOException
     */
    private String passSolidCommand(String solidCommand, String commandPrompt) throws IOException {
        String commands[] = solidCommand.split(solidMark);
        for (int i = 0; i < commands.length - 1; i++) {
            write(commands[i]);
        }
        return passCommand(commands[commands.length - 1], commandPrompt);
    }

    /**
     * Send to device command, which use ip address. Command must contain ipMark
     * (the combination of characters, which set in config file), define
     * position and value of octets of ip address.
     *
     * @param ipCommand command, whinch you want to add the ip
     * @param commandPrompt the combination of characters, which device output,
     * when be ready to take next
     * @return response from device to entered command
     * @throws IOException
     */
    private String passIpCommand(String ipCommand, String commandPrompt) throws IOException {
        String ips[] = ip.split("\\.");

        if (ipCommand.contains(ipMark + "1")) {
            ipCommand = ipCommand.replaceAll(ipMark + "1", ips[3]);
        } else if (ipCommand.contains(ipMark + "2")) {
            ipCommand = ipCommand.replaceAll(ipMark + "2", ips[2] + "." + ips[3]);
        } else if (ipCommand.contains(ipMark + "3")) {
            ipCommand = ipCommand.replaceAll(ipMark + "3", ips[1] + "." + ips[2] + "." + ips[3]);

        } else if (ipCommand.contains(ipMark + "4")) {
            ipCommand = ipCommand.replaceAll(ipMark + "4", ip);
        } else {
            ipCommand = ipCommand.replaceAll(ipMark, ip);
        }

        return passCommand(ipCommand, commandPrompt);
    }

    /**
     * Analys of input stream and waiting for string prompt
     *
     * @param prompt string, which expected from device
     * @return response from device
     * @throws IOException
     */
    private String readUntil(String prompt) throws IOException {
        StringBuilder sb = new StringBuilder();
        while (!sb.toString().endsWith(prompt)) {
            sb.append((char) in.read());
        }
        return sb.toString();
    }

    /**
     * Analys of input stream and waiting for string prompt or reservePrompt
     *
     * @param prompt string, which expected from device
     * @param reservePrompt alternative expected string
     * @return response from device
     * @throws IOException
     */
    private String readUntil(String prompt, String reservePrompt) throws IOException {
        StringBuilder sb = new StringBuilder();
        while (!(sb.toString().endsWith(prompt) || sb.toString().endsWith(reservePrompt))) {
            sb.append((char) in.read());
        }
        return sb.toString();
    }

    /**
     * Send data to output stream for pass to devicee
     *
     * @param value data for out
     */
    private void write(String value) {
        try {
            out.println(value);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

/**
 * Ecxeption, when authorization is failed
 *
 * @author rs
 */
class LoginFailedException extends Exception {

    LoginFailedException(String login, String report) {
        super("Authorization failed, login: \"" + login + "\", status:" + report);
    }

}

/**
 * Enumiration types of error analysis. ERROR - if you have response - it's
 * error, SUCCESS - response contains string of Success, OFF - analysis is not
 * possible
 *
 * @author rs
 */
enum AnalysisMode {
    ERROR, SUCCESS, OFF;
}