org.jumpmind.symmetric.transport.internal.InternalTransportManager.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.transport.internal.InternalTransportManager.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.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.NotImplementedException;
import org.jumpmind.symmetric.AbstractSymmetricEngine;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.io.IoConstants;
import org.jumpmind.symmetric.model.BatchAck;
import org.jumpmind.symmetric.model.ChannelMap;
import org.jumpmind.symmetric.model.IncomingBatch;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.model.OutgoingBatch;
import org.jumpmind.symmetric.model.ProcessInfo;
import org.jumpmind.symmetric.model.ProcessInfoKey;
import org.jumpmind.symmetric.model.ProcessType;
import org.jumpmind.symmetric.model.ProcessInfo.Status;
import org.jumpmind.symmetric.transport.AbstractTransportManager;
import org.jumpmind.symmetric.transport.IIncomingTransport;
import org.jumpmind.symmetric.transport.IOutgoingTransport;
import org.jumpmind.symmetric.transport.IOutgoingWithResponseTransport;
import org.jumpmind.symmetric.transport.ITransportManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Coordinates interaction between two symmetric engines in the same JVM.
 */
public class InternalTransportManager extends AbstractTransportManager implements ITransportManager {

    static final Logger log = LoggerFactory.getLogger(InternalTransportManager.class);

    protected ISymmetricEngine symmetricEngine;

    public InternalTransportManager(ISymmetricEngine engine) {
        super(engine.getExtensionService());
        this.symmetricEngine = engine;
    }

    public IIncomingTransport getFilePullTransport(Node remote, final Node local, String securityToken,
            Map<String, String> requestProperties, String registrationUrl) throws IOException {
        final PipedOutputStream respOs = new PipedOutputStream();
        final PipedInputStream respIs = new PipedInputStream(respOs);

        runAtClient(remote.getSyncUrl(), null, respOs, new IClientRunnable() {
            public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception {
                IOutgoingTransport transport = new InternalOutgoingTransport(respOs, null);
                ProcessInfo processInfo = engine.getStatisticManager()
                        .newProcessInfo(new ProcessInfoKey(engine.getNodeService().findIdentityNodeId(),
                                local.getNodeId(), ProcessType.FILE_SYNC_PULL_HANDLER));
                try {
                    engine.getFileSyncService().sendFiles(processInfo, local, transport);
                    processInfo.setStatus(Status.OK);
                } catch (RuntimeException ex) {
                    processInfo.setStatus(Status.ERROR);
                    throw ex;
                }
                transport.close();
            }
        });
        return new InternalIncomingTransport(respIs);
    }

    public IIncomingTransport getPullTransport(Node remote, final Node local, String securityToken,
            Map<String, String> requestProperties, String registrationUrl) throws IOException {
        final PipedOutputStream respOs = new PipedOutputStream();
        final PipedInputStream respIs = new PipedInputStream(respOs);

        final ChannelMap suspendIgnoreChannels = symmetricEngine.getConfigurationService()
                .getSuspendIgnoreChannelLists(remote.getNodeId());

        runAtClient(remote.getSyncUrl(), null, respOs, new IClientRunnable() {
            public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception {
                IOutgoingTransport transport = new InternalOutgoingTransport(respOs, suspendIgnoreChannels,
                        IoConstants.ENCODING);
                ProcessInfo processInfo = engine.getStatisticManager().newProcessInfo(new ProcessInfoKey(
                        engine.getNodeService().findIdentityNodeId(), local.getNodeId(), ProcessType.PULL_HANDLER));
                try {
                    engine.getDataExtractorService().extract(processInfo, local, transport);
                    processInfo.setStatus(Status.OK);
                } catch (RuntimeException ex) {
                    processInfo.setStatus(Status.ERROR);
                    throw ex;
                }
                transport.close();
            }
        });
        return new InternalIncomingTransport(respIs);
    }

    public IOutgoingWithResponseTransport getPushTransport(final Node targetNode, final Node sourceNode,
            String securityToken, String channelId, String registrationUrl) throws IOException {
        final PipedOutputStream pushOs = new PipedOutputStream();
        final PipedInputStream pushIs = new PipedInputStream(pushOs);

        final PipedOutputStream respOs = new PipedOutputStream();
        final PipedInputStream respIs = new PipedInputStream(respOs);

        runAtClient(targetNode.getSyncUrl(), pushIs, respOs, new IClientRunnable() {
            public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception {
                // This should be basically what the push servlet does ...
                engine.getDataLoaderService().loadDataFromPush(sourceNode, pushIs, respOs);
            }
        });
        return new InternalOutgoingWithResponseTransport(pushOs, respIs);
    }

    public IOutgoingWithResponseTransport getFilePushTransport(final Node targetNode, final Node sourceNode,
            String securityToken, String registrationUrl) throws IOException {
        final PipedOutputStream pushOs = new PipedOutputStream();
        final PipedInputStream pushIs = new PipedInputStream(pushOs);

        final PipedOutputStream respOs = new PipedOutputStream();
        final PipedInputStream respIs = new PipedInputStream(respOs);

        runAtClient(targetNode.getSyncUrl(), pushIs, respOs, new IClientRunnable() {
            public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception {
                // This should be basically what the push servlet does ...
                engine.getFileSyncService().loadFilesFromPush(sourceNode.getNodeId(), is, os);
            }
        });
        return new InternalOutgoingWithResponseTransport(pushOs, respIs);
    }

    public IIncomingTransport getRegisterTransport(final Node client, String registrationUrl) throws IOException {

        final PipedOutputStream respOs = new PipedOutputStream();
        final PipedInputStream respIs = new PipedInputStream(respOs);

        runAtClient(registrationUrl, null, respOs, new IClientRunnable() {
            public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception {
                // This should be basically what the registration servlet does
                // ...
                engine.getRegistrationService().registerNode(client, os, false);
            }
        });
        return new InternalIncomingTransport(respIs);
    }

    @Override
    public int sendCopyRequest(Node local) throws IOException {
        return -1;
    }

    public int sendAcknowledgement(Node remote, List<IncomingBatch> list, Node local, String securityToken,
            String registrationUrl) throws IOException {
        try {
            if (list != null && list.size() > 0) {
                ISymmetricEngine remoteEngine = getTargetEngine(remote.getSyncUrl());
                String ackData = getAcknowledgementData(remote.requires13Compatiblity(), local.getNodeId(), list);
                List<BatchAck> batches = readAcknowledgement(ackData);
                for (BatchAck batchInfo : batches) {
                    remoteEngine.getAcknowledgeService().ack(batchInfo);
                }
            }
            return HttpURLConnection.HTTP_OK;
        } catch (Exception ex) {
            log.error("", ex);
            return -1;
        }
    }

    public void writeAcknowledgement(OutputStream out, Node remote, List<IncomingBatch> list, Node local,
            String securityToken) throws IOException {
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, IoConstants.ENCODING), true);
        pw.println(getAcknowledgementData(remote.requires13Compatiblity(), local.getNodeId(), list));
        pw.close();
    }

    private void runAtClient(final String url, final InputStream is, final OutputStream os,
            final IClientRunnable runnable) {
        new Thread() {
            public void run() {
                try {
                    ISymmetricEngine engine = getTargetEngine(url);
                    runnable.run(engine, is, os);
                } catch (Exception e) {
                    log.error("", e);
                } finally {
                    IOUtils.closeQuietly(is);
                    IOUtils.closeQuietly(os);
                }
            }
        }.start();
    }

    private ISymmetricEngine getTargetEngine(String url) {
        ISymmetricEngine engine = AbstractSymmetricEngine.findEngineByUrl(url);
        if (engine == null) {
            throw new NullPointerException("Could not find the engine reference for the following url: " + url);
        } else {
            return engine;
        }
    }

    @Override
    public IIncomingTransport getAckStatusTransport(OutgoingBatch batch, Node remote, Node local,
            String securityToken, String registrationUrl) {
        throw new NotImplementedException();
    }

    @Override
    public void makeReservationTransport(String poolId, String channelId, Node remote, Node local,
            String securityToken, String registrationUrl) {
    }

    interface IClientRunnable {
        public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception;
    }

}