Java tutorial
/* * Copyright 2015 crea-doo.at * * 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 at.creadoo.util.netio; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.net.UnknownHostException; import java.security.NoSuchAlgorithmException; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; public class NetIO { private static final Logger log = Logger.getLogger(NetIO.class); private static final Integer MAX_RETRIES = 5; private final String host; private final Integer port; private final String user; private final String pass; protected Socket socket; protected BufferedReader reader; protected BufferedWriter writer; protected State state; private String hash; protected NetIO(final NetIOBuilder builder) { this.state = State.DISCONNECTED; this.host = builder.host.trim(); this.port = builder.port; this.user = builder.user.trim(); this.pass = builder.pass.trim(); } public Boolean isConnected() { return State.CONNECTED.equals(state) || isAuthorized(); } public Boolean isAuthorized() { return State.AUTHORIZED.equals(state); } /** * Returns the firmware version */ public String getVersion() throws NetIOException { return getResponseMessage(command("version")); } /** * Returns the uptime of the device */ public String getUpTime() throws NetIOException { return getResponseMessage(command("uptime")); } /** * Returns the MAC address of the device */ public String getMAC() throws NetIOException { return getResponseMessage(command("system mac")); } /** * Returns the current time */ public String getTime() throws NetIOException { return getResponseMessage(command("system time")); } /** * Returns the HTTP port */ public Integer getHTTPPort() throws NetIOException { try { return Integer.parseInt(getResponseMessage(command("system webport"))); } catch (NumberFormatException ex) { // } return null; } /** * Returns the HTTP port */ public Integer getKShellPort() throws NetIOException { try { return Integer.parseInt(getResponseMessage(command("system kshport"))); } catch (NumberFormatException ex) { // } return null; } /** * Returns the name of the device */ public String getAlias() throws NetIOException { return stripQuotes(getResponseMessage(command("alias"))); } /** * Sets the name of the device */ public Boolean setAlias(final String alias) throws NetIOException { if (alias != null && !alias.isEmpty()) { return isResponseCodeOk(command("alias " + alias)); } return false; } /** * Reboot the device */ public Boolean reboot() throws NetIOException { if (isConnected()) { final String response = command("reboot"); final ResponseCode responseCode = getResponseCode(response); if (responseCode.equals(ResponseCode.HELLO) || responseCode.equals(ResponseCode.REBOOTING)) { this.state = State.DISCONNECTED; return true; } } return false; } /** * Disconnect from the device */ public Boolean disconnect() { log.debug("Disconnect"); if (isConnected()) { this.state = State.DISCONNECTED; this.hash = ""; IOUtils.closeQuietly(this.socket); this.socket = null; IOUtils.closeQuietly(this.reader); this.reader = null; IOUtils.closeQuietly(this.writer); this.writer = null; return true; } return false; } /** * Returns the port status of all ports or of the given port if set */ public PortStatus getPortStatus(final Integer port) throws NetIOException { if (isPortValid(port)) { return PortStatus.getPortStatus(getResponseMessage(command("port " + port.toString()))); } return null; } /** * Checks if port is enabled */ public Boolean isPortOn(final Integer port) throws NetIOException { if (isPortValid(port)) { final String response = command("port " + port); return isResponseCodeOk(response) && "1".equals(getResponseMessage(response)); } return false; } /** * Checks if port is disabled */ public Boolean isPortOff(final Integer port) throws NetIOException { return !isPortOn(port); } /** * Enable port */ public Boolean setPortOn(final Integer port) throws NetIOException { if (isPortValid(port) && isPortOff(port)) { return isResponseCodeOk(command("port " + port + " " + PortStatus.ACTIVATED.getValue())); } return false; } /** * Disable port */ public Boolean setPortOff(final Integer port) throws NetIOException { if (isPortValid(port) && isPortOn(port)) { return isResponseCodeOk(command("port " + port + " " + PortStatus.DEACTIVATED.getValue())); } return false; } /** * Enable all ports */ public Boolean setPortsOn() throws NetIOException { return isResponseCodeOk(command("port list 1111")); } /** * Disable all ports */ public Boolean setPortsOff() throws NetIOException { return isResponseCodeOk(command("port list 0000")); } /** * Set all ports at once */ public Boolean setPorts(final String command) throws NetIOException { log.trace("send(" + command + ")"); if (command == null || !command.matches("^[01iu]{4}$")) { final String error = "Invalid format (" + command + ")"; log.debug(error); throw new NetIOException(error); } return isResponseCodeOk(command("port list " + command)); } /** * Toggle port */ public Boolean togglePort(final Integer port) throws NetIOException { if (isPortValid(port)) { if (isPortOn(port)) { return setPortOff(port); } else { return setPortOn(port); } } return false; } /** * Set port mode to manual operation */ public Boolean setPortManual(final Integer port) throws NetIOException { if (isPortValid(port)) { return isResponseCodeOk(command("port " + port + " manual")); } return false; } /** * Returns settings for a given port */ public String getPortSetup(final Integer port) throws NetIOException { if (isPortValid(port)) { return getResponseMessage(command("port setup " + port)); } return null; } /** * Returns name for a given port */ public String getPortName(final Integer port) throws NetIOException { if (isPortValid(port)) { final String response = getPortSetup(port); final String regex = "^\"?(.+?)\"?\\s(.+?)\\s(.+?)\\s(.+?)"; final Pattern pattern = Pattern.compile(regex); final Matcher matcher = pattern.matcher(response); if (matcher.matches() && matcher.groupCount() == 4) { return stripQuotes(matcher.group(1)); } } return null; } /** * Returns name for a given port */ private String stripQuotes(final String content) { String tempContent = content.trim(); if (tempContent.startsWith("\"")) { tempContent = tempContent.substring(1); } if (tempContent.endsWith("\"")) { tempContent = tempContent.substring(0, tempContent.length() - 2); } return tempContent; } /** * Validates port */ public Boolean isPortValid(final Integer port) { if (port != null && (port >= 1) && (port <= 4)) { return true; } return false; } /** * Checks if a response has the response code "250 OK" */ private Boolean isResponseCodeOk(final String response) { return checkResponseCode(response, ResponseCode.OK); } /** * Checks if a response has the desired response code */ private Boolean checkResponseCode(final String response, final ResponseCode code) { if (response != null && code != null && code.equals(getResponseCode(response))) { return true; } return false; } /** * Extracts the return code out of a response */ private ResponseCode getResponseCode(final String response) { if (response == null || response.trim().isEmpty()) { return null; } final String tempResponse = response.trim(); if ((tempResponse.length() < 3) && !(tempResponse.length() > 4)) { return null; } if (!tempResponse.substring(3, 4).equals(" ")) { return null; } try { final Integer code = Integer.parseInt(tempResponse.substring(0, 3)); final ResponseCode responseCode = ResponseCode.getResponseCode(code); if (responseCode != null) { return responseCode; } } catch (NumberFormatException ex) { // } return null; } /** * Extracts the return code out of a response */ private String getResponseMessage(final String response) { if (response == null || response.trim().isEmpty()) { return null; } final String tempResponse = response.trim(); if ((tempResponse.length() < 3) && !(tempResponse.length() > 4)) { return null; } return tempResponse.substring(4).trim(); } /** * Sends a command to the device */ protected String command(final String command) throws NetIOException { return command(command, 0); } protected String command(final String command, final Integer retryCount) throws NetIOException { try { if (!isAuthorized() && !authorize()) { final String error = "Unable to authorize"; log.debug(error); throw new NetIOException(error); } log.debug("--> " + command); writer.write(command); writer.newLine(); writer.flush(); final String response = reader.readLine(); log.debug("<-- " + response); return response; } catch (IOException ex) { disconnect(); if (retryCount < MAX_RETRIES) { return command(command, retryCount + 1); } else { throw new NetIOException("Error while sending command", ex); } } } private Boolean authorize() throws NetIOException { try { if (!isConnected()) { connect(); } final String sendString = "clogin " + user + " " + getPasswordHash(); log.debug("--> " + sendString); writer.write(sendString); writer.newLine(); writer.flush(); final String response = reader.readLine(); log.debug("<-- " + response); if (!isResponseCodeOk(response)) { throw new IOException(response); } state = State.AUTHORIZED; return true; } catch (NetIOException ex) { log.error("Error while connecting to " + host + ":" + port, ex); } catch (NoSuchAlgorithmException ex) { throw new NetIOException(ex); } catch (IOException ex) { throw new NetIOException(ex); } return false; } private void connect() throws NetIOException { try { if (host == null || host.isEmpty()) { throw new NetIOException("Can't connect to invalid host"); } if (port == null) { throw new NetIOException("Can't connect to host with invalid port"); } socket = new Socket(host, port); reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), Constants.DEFAULT_CHARSET)); writer = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), Constants.DEFAULT_CHARSET)); final String response = reader.readLine(); log.debug("<-- " + response); if (checkResponseCode(response, ResponseCode.HELLO)) { hash = response.substring(10, 18).trim(); state = State.CONNECTED; } } catch (UnknownHostException ex) { state = State.DISCONNECTED; throw new NetIOException("Error while connecting", ex); } catch (IOException ex) { state = State.DISCONNECTED; throw new NetIOException("Error while connecting", ex); } } private String getPasswordHash() throws NoSuchAlgorithmException, UnsupportedEncodingException { return Hex.encodeHexString( (DigestUtils.getMd5Digest().digest((user + pass + hash).getBytes(Constants.DEFAULT_CHARSET)))); } }