io.github.thred.climatetray.mnet.request.AbstractMNetRequest.java Source code

Java tutorial

Introduction

Here is the source code for io.github.thred.climatetray.mnet.request.AbstractMNetRequest.java

Source

/*
 * Copyright 2015, 2016 Manfred Hantschel
 *
 * This file is part of Climate-Tray.
 *
 * Climate-Tray is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the License, or any later version.
 *
 * Climate-Tray is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with Climate-Tray. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package io.github.thred.climatetray.mnet.request;

import static io.github.thred.climatetray.ClimateTray.*;
import io.github.thred.climatetray.ClimateTray;
import io.github.thred.climatetray.mnet.MNetDevice;
import io.github.thred.climatetray.util.DomBuilder;
import io.github.thred.climatetray.util.DomUtils;
import io.github.thred.climatetray.util.Utils;
import io.github.thred.climatetray.util.message.Message;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

public abstract class AbstractMNetRequest implements MNetRequest {

    public AbstractMNetRequest() {
        super();
    }

    @Override
    public final void execute(URL url, String... additionalProxyExcludes) throws MNetRequestException {
        try {
            String content = buildRequest();
            StringEntity body = new StringEntity(content);
            CloseableHttpClient client = ClimateTray.PREFERENCES.getProxySettings()
                    .createHttpClient(additionalProxyExcludes);
            HttpPost post = new HttpPost(url.toURI());

            post.setHeader("content-type", "text/xml");
            post.setEntity(body);

            LOG.debug("Sending request to \"%s\". The request is:\n%s", url.toExternalForm(), content);

            CloseableHttpResponse response;

            try {
                response = client.execute(post);
            } catch (IOException e) {
                throw new MNetRequestException("Failed to send request to \"%s\".", e, url.toExternalForm())
                        .hint(Message.error(
                                "Could not contact the centralized controller.\n\nThis usually indicates, that the value of the field \"Controller Address\" is wrong. "
                                        + "If you are sure, that the value is correct, there may be a firewall or a proxy in the way. "
                                        + "Try to call the URL \"%s\" in a browser.",
                                url.toExternalForm()));
            }

            try {
                int status = response.getStatusLine().getStatusCode();

                if ((status >= 200) && (status < 300)) {
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        try {
                            InputStream in = entity.getContent();

                            try {
                                if (LOG.isDebugEnabled()) {
                                    byte[] bytes = Utils.toByteArray(in);

                                    LOG.debug("Reading response from \"%s\". The response is:\n%s",
                                            url.toExternalForm(), new String(bytes, "UTF-8"));

                                    in = new ByteArrayInputStream(bytes);
                                }

                                parseResponse(in);
                            } finally {
                                in.close();
                            }
                        } catch (MNetRequestException e) {
                            throw e;
                        } catch (Exception e) {
                            throw new MNetRequestException("Failed to parse response from \"%s\".", e,
                                    url.toExternalForm())
                                            .hint(Message.error("The parsing of the response failed.\n\n"
                                                    + "The request hit a server, but it may be the wrong one (the log may contain a more detailed description). "
                                                    + "Check the contents of the field \"Controller Address\" or try to call the URL \"%s\" in a browser.",
                                                    url.toExternalForm()));
                        }
                    }
                } else {
                    throw new MNetRequestException("Request to \"%s\" failed with error %d.", url.toExternalForm(),
                            status).hint(
                                    Message.error("The request failed with error %d.\n\n"
                                            + "The request hit a server, but it may be the wrong one. "
                                            + "Check the contents of the field \"Controller Address\" again or try to call the URL \"%s\" in a browser.",
                                            status, url.toExternalForm()));
                }
            } finally {
                response.close();
            }
        } catch (MNetRequestException e) {
            throw e;
        } catch (Exception e) {
            throw new MNetRequestException("Sending an request to \"%s\" failed with an unhandled error: %s.", e,
                    url.toExternalForm(), e.toString())
                            .hint(Message.error(
                                    "The request failed for some unknown reason.\n\nYou can check the log for the detailed exception."));
        }
    }

    protected final String buildRequest() throws MNetRequestException {
        DomBuilder builder = new DomBuilder();

        builder.begin("Packet");
        {
            builder.element("Command", getRequestCommand());
            builder.begin("DatabaseManager");
            {
                buildRequestContent(builder);
            }
            builder.end();
        }
        builder.end();

        return DomUtils.toString(builder.getDocument());
    }

    protected abstract String getRequestCommand();

    protected abstract void buildRequestContent(DomBuilder builder) throws MNetRequestException;

    public void parseResponse(InputStream inputStream) throws IOException, MNetRequestException {
        Document document = DomUtils.read(inputStream);
        Node errorNode = DomUtils.find(document, "//ERROR");

        if (errorNode != null) {
            String point = DomUtils.getAttribute(errorNode, "Point");
            String code = DomUtils.getAttribute(errorNode, "Code");
            String message = DomUtils.getAttribute(errorNode, "Message");

            MNetRequestException e;

            if (Utils.isBlank(point)) {
                e = new MNetRequestException("The response contained the error \"%s\" (%s).", message, code);
            } else {
                e = new MNetRequestException("The response contained the error \"%s\" (%s) at %s.", message, code,
                        point);
            }

            throw e.hint(Message.error("The response contained the error \"%s\".\n\n"
                    + "This indicates that the centralized controller was successfully contacted, but it did not understand the request. "
                    + "Please make sure that the values of the fields \"EC\" and \"Air Conditioner Address\" are correct.",
                    message));
        }

        parseResponseContent(document);
    }

    protected abstract void parseResponseContent(Node document) throws MNetRequestException;

    public String describe(MNetDevice device) {
        try {
            return buildRequest();
        } catch (MNetRequestException e) {
            LOG.error("Failed to describe request.", e);

            return String.format("Failed to describe request: %s", e.toString());
        }
    }
}