org.jumpmind.symmetric.transport.http.HttpOutgoingTransport.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.transport.http.HttpOutgoingTransport.java

Source

/**
 * Licensed to JumpMind Inc under one or more contributor
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) along with this library; if not, see
 * <http://www.gnu.org/licenses/>.
 *
 * 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 org.jumpmind.symmetric.transport.http;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.io.IOUtils;
import org.jumpmind.exception.IoException;
import org.jumpmind.symmetric.io.IoConstants;
import org.jumpmind.symmetric.model.ChannelMap;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.transport.IOutgoingWithResponseTransport;
import org.jumpmind.symmetric.util.SymmetricUtils;
import org.jumpmind.symmetric.web.WebConstants;

public class HttpOutgoingTransport implements IOutgoingWithResponseTransport {

    static final String CRLF = "\r\n";

    private String boundary;

    private URL url;

    private OutputStream os;

    private BufferedWriter writer;

    private BufferedReader reader;

    private HttpURLConnection connection;

    private int httpTimeout;

    private boolean useCompression;

    private int compressionStrategy;

    private int compressionLevel;

    private String basicAuthUsername;

    private String basicAuthPassword;

    private boolean streamOutputEnabled = false;

    private int streamOutputChunkSize = 30720;

    private boolean fileUpload = false;

    public HttpOutgoingTransport(URL url, int httpTimeout, boolean useCompression, int compressionStrategy,
            int compressionLevel, String basicAuthUsername, String basicAuthPassword, boolean streamOutputEnabled,
            int streamOutputSize, boolean fileUpload) {
        this.url = url;
        this.httpTimeout = httpTimeout;
        this.useCompression = useCompression;
        this.compressionLevel = compressionLevel;
        this.compressionStrategy = compressionStrategy;
        this.basicAuthUsername = basicAuthUsername;
        this.basicAuthPassword = basicAuthPassword;
        this.streamOutputChunkSize = streamOutputSize;
        this.streamOutputEnabled = streamOutputEnabled;
        this.fileUpload = fileUpload;
    }

    public void close() {
        closeWriter(true);
        closeOutputStream(true);
        closeReader();
        if (connection != null) {
            connection.disconnect();
            connection = null;
        }
    }

    private void closeReader() {
        if (reader != null) {
            IOUtils.closeQuietly(reader);
            reader = null;
        }
    }

    private void closeOutputStream(boolean closeQuietly) {
        if (os != null) {
            try {
                if (fileUpload) {
                    IOUtils.write(CRLF + "--" + boundary + "--" + CRLF, os);
                }
                os.flush();
            } catch (IOException ex) {
                throw new IoException(ex);
            } finally {
                if (closeQuietly) {
                    IOUtils.closeQuietly(os);
                } else {
                    try {
                        os.close();
                    } catch (IOException ex) {
                        throw new IoException(ex);
                    }
                }
                os = null;
            }
        }
    }

    private void closeWriter(boolean closeQuietly) {
        if (writer != null) {
            try {
                if (fileUpload) {
                    IOUtils.write(CRLF + "--" + boundary + "--" + CRLF, os);
                }
                writer.flush();
            } catch (IOException ex) {
                throw new IoException(ex);
            } finally {
                if (closeQuietly) {
                    IOUtils.closeQuietly(writer);
                } else {
                    try {
                        writer.close();
                    } catch (IOException ex) {
                        throw new IoException(ex);
                    }
                }
                writer = null;
                os = null;
            }
        }
    }

    /**
     * Before streaming data to the remote node, make sure it is ok to. We have
     * found that we can be more efficient on a push by relying on HTTP
     * keep-alive.
     *
     * @throws IOException
     * @throws {@link ConnectionRejectedException}
     * @throws {@link AuthenticationException}
     */
    private HttpURLConnection requestReservation() {
        try {
            connection = HttpTransportManager.openConnection(url, basicAuthUsername, basicAuthPassword);
            connection.setUseCaches(false);
            connection.setConnectTimeout(httpTimeout);
            connection.setReadTimeout(httpTimeout);
            connection.setRequestMethod("HEAD");

            SymmetricUtils.analyzeResponseCode(connection.getResponseCode());
        } catch (IOException ex) {
            throw new IoException(ex);
        }
        return connection;
    }

    public OutputStream openStream() {
        try {
            connection = HttpTransportManager.openConnection(url, basicAuthUsername, basicAuthPassword);
            if (streamOutputEnabled) {
                connection.setChunkedStreamingMode(streamOutputChunkSize);
            }
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setConnectTimeout(httpTimeout);
            connection.setReadTimeout(httpTimeout);

            boundary = Long.toHexString(System.currentTimeMillis());
            if (!fileUpload) {
                connection.setRequestMethod("PUT");
                connection.setRequestProperty("Accept-Encoding", "gzip");
                if (useCompression) {
                    connection.addRequestProperty("Content-Type", "gzip"); // application/x-gzip?
                }
            } else {
                connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            }

            os = connection.getOutputStream();

            if (!fileUpload && useCompression) {
                os = new GZIPOutputStream(os) {
                    {
                        this.def.setLevel(compressionLevel);
                        this.def.setStrategy(compressionStrategy);
                    }
                };
            }

            if (fileUpload) {
                final String fileName = "file.zip";
                IOUtils.write("--" + boundary + CRLF, os);
                IOUtils.write(
                        "Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + fileName + "\"" + CRLF,
                        os);
                IOUtils.write("Content-Type: " + URLConnection.guessContentTypeFromName(fileName) + CRLF, os);
                IOUtils.write("Content-Transfer-Encoding: binary" + CRLF + CRLF, os);
                os.flush();

            }
            return os;
        } catch (IOException ex) {
            throw new IoException(ex);
        }
    }

    public BufferedWriter openWriter() {
        try {
            OutputStreamWriter wout = new OutputStreamWriter(openStream(), IoConstants.ENCODING);
            writer = new BufferedWriter(wout);
            return writer;
        } catch (IOException ex) {
            throw new IoException(ex);
        }
    }

    public BufferedReader readResponse() throws IOException {
        closeWriter(false);
        closeOutputStream(false);
        SymmetricUtils.analyzeResponseCode(connection.getResponseCode());
        this.reader = HttpTransportManager.getReaderFrom(connection);
        return this.reader;
    }

    public boolean isOpen() {
        return connection != null;
    }

    public ChannelMap getSuspendIgnoreChannelLists(IConfigurationService configurationService, Node targetNode) {

        HttpURLConnection connection = requestReservation();

        // Connection contains remote suspend/ignore channels list if
        // reservation was successful.

        ChannelMap suspendIgnoreChannelsList = new ChannelMap();

        String suspends = connection.getHeaderField(WebConstants.SUSPENDED_CHANNELS);
        String ignores = connection.getHeaderField(WebConstants.IGNORED_CHANNELS);

        suspendIgnoreChannelsList.addSuspendChannels(suspends);
        suspendIgnoreChannelsList.addIgnoreChannels(ignores);

        ChannelMap localSuspendIgnoreChannelsList = configurationService
                .getSuspendIgnoreChannelLists(targetNode.getNodeId());
        suspendIgnoreChannelsList.addSuspendChannels(localSuspendIgnoreChannelsList.getSuspendChannels());
        suspendIgnoreChannelsList.addIgnoreChannels(localSuspendIgnoreChannelsList.getIgnoreChannels());

        return suspendIgnoreChannelsList;
    }

}