org.jumpmind.symmetric.service.impl.PullService.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.service.impl.PullService.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.service.impl;

import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.db.ISymmetricDialect;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.model.NodeCommunication;
import org.jumpmind.symmetric.model.NodeCommunication.CommunicationType;
import org.jumpmind.symmetric.model.RemoteNodeStatus;
import org.jumpmind.symmetric.model.RemoteNodeStatuses;
import org.jumpmind.symmetric.service.ClusterConstants;
import org.jumpmind.symmetric.service.IClusterService;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IDataLoaderService;
import org.jumpmind.symmetric.service.IExtensionService;
import org.jumpmind.symmetric.service.INodeCommunicationService;
import org.jumpmind.symmetric.service.INodeCommunicationService.INodeCommunicationExecutor;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.symmetric.service.IPullService;
import org.jumpmind.symmetric.service.IRegistrationService;
import org.jumpmind.symmetric.transport.OfflineException;

/**
 * @see IPullService
 */
public class PullService extends AbstractOfflineDetectorService
        implements IPullService, INodeCommunicationExecutor {

    private INodeService nodeService;

    private IRegistrationService registrationService;

    private IClusterService clusterService;

    private INodeCommunicationService nodeCommunicationService;

    private IDataLoaderService dataLoaderService;

    private IConfigurationService configurationService;

    public PullService(IParameterService parameterService, ISymmetricDialect symmetricDialect,
            INodeService nodeService, IDataLoaderService dataLoaderService,
            IRegistrationService registrationService, IClusterService clusterService,
            INodeCommunicationService nodeCommunicationService, IConfigurationService configurationService,
            IExtensionService extensionService) {
        super(parameterService, symmetricDialect, extensionService);
        this.nodeService = nodeService;
        this.registrationService = registrationService;
        this.clusterService = clusterService;
        this.nodeCommunicationService = nodeCommunicationService;
        this.dataLoaderService = dataLoaderService;
        this.configurationService = configurationService;
    }

    synchronized public RemoteNodeStatuses pullData(boolean force) {
        final RemoteNodeStatuses statuses = new RemoteNodeStatuses(configurationService.getChannels(false));
        Node identity = nodeService.findIdentity(false);
        if (identity == null || identity.isSyncEnabled()) {
            long minimumPeriodMs = parameterService.getLong(ParameterConstants.PULL_MINIMUM_PERIOD_MS, -1);
            if (force || !clusterService.isInfiniteLocked(ClusterConstants.PULL)) {
                // register if we haven't already been registered
                registrationService.registerWithServer();
                identity = nodeService.findIdentity(false);
                if (identity != null) {
                    List<NodeCommunication> nodes = nodeCommunicationService.list(CommunicationType.PULL);
                    int availableThreads = nodeCommunicationService.getAvailableThreads(CommunicationType.PULL);
                    for (NodeCommunication nodeCommunication : nodes) {
                        boolean meetsMinimumTime = true;
                        if (minimumPeriodMs > 0 && nodeCommunication.getLastLockTime() != null
                                && (System.currentTimeMillis()
                                        - nodeCommunication.getLastLockTime().getTime()) < minimumPeriodMs) {
                            meetsMinimumTime = false;
                        }
                        if (availableThreads > 0 && meetsMinimumTime) {
                            if (nodeCommunicationService.execute(nodeCommunication, statuses, this)) {
                                availableThreads--;
                            }
                        }
                    }
                }
            } else {
                log.debug("Did not run the pull process because it has been stopped");
            }
        }

        return statuses;
    }

    public void execute(NodeCommunication nodeCommunication, RemoteNodeStatus status) {
        Node node = nodeCommunication.getNode();
        if (StringUtils.isNotBlank(node.getSyncUrl()) || !parameterService.isRegistrationServer()) {
            int pullCount = 0;
            long batchesProcessedCount = 0;
            do {
                batchesProcessedCount = status.getBatchesProcessed();
                pullCount++;
                log.debug("Pull requested for {}", node.toString());
                if (pullCount > 1) {
                    log.info("Immediate pull requested while in reload mode");
                }

                try {
                    dataLoaderService.loadDataFromPull(node, status);
                } catch (ConnectException ex) {
                    log.warn("Failed to connect to the transport: {}",
                            (node.getSyncUrl() == null ? parameterService.getRegistrationUrl()
                                    : node.getSyncUrl()));
                    fireOffline(ex, node, status);
                } catch (OfflineException ex) {
                    fireOffline(ex, node, status);
                } catch (UnknownHostException ex) {
                    fireOffline(ex, node, status);
                } catch (SocketException ex) {
                    log.warn("{}", ex.getMessage());
                    fireOffline(ex, node, status);
                } catch (IOException ex) {
                    log.error("An IO exception happened while attempting to pull data", ex);
                    fireOffline(ex, node, status);
                }

                if (!status.failed() && (status.getDataProcessed() > 0 || status.getBatchesProcessed() > 0)) {
                    log.info("Pull data received from {}.  {} rows and {} batches were processed", new Object[] {
                            node.toString(), status.getDataProcessed(), status.getBatchesProcessed() });

                } else if (status.failed()) {
                    log.info(
                            "There was a failure while pulling data from {}.  {} rows and {} batches were processed",
                            new Object[] { node.toString(), status.getDataProcessed(),
                                    status.getBatchesProcessed() });
                }
                /*
                 * Re-pull immediately if we are in the middle of an initial
                 * load so that the initial load completes as quickly as
                 * possible.
                 */
            } while (nodeService.isDataLoadStarted() && !status.failed()
                    && status.getBatchesProcessed() > batchesProcessedCount);

        } else {
            log.warn("Cannot pull node '{}' in the group '{}'.  The sync url is blank", node.getNodeId(),
                    node.getNodeGroupId());
        }
    }

}