org.v2020.service.ie.VnaImport.java Source code

Java tutorial

Introduction

Here is the source code for org.v2020.service.ie.VnaImport.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Daniel Murygin.
 *
 * This program is free software: you can redistribute it and/or 
 * modify it under the terms of the GNU Lesser General Public License 
 * as published by the Free Software Foundation, either version 3 
 * of the License, or (at your option) any later version.
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. 
 * If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Daniel Murygin <dm[at]sernet[dot]de> - initial API and implementation
 ******************************************************************************/
package org.v2020.service.ie;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.v2020.data.entity.Node;

import de.sernet.sync.data.SyncLink;
import de.sernet.sync.data.SyncObject;
import de.sernet.sync.mapping.SyncMapping.MapObjectType;

/**
 * @author Daniel Murygin <dm[at]sernet[dot]de>
 */
@Service("vnaImport")
public class VnaImport implements IVnaImport {

    private static final Logger LOG = LoggerFactory.getLogger(VnaImport.class);

    private static final int DEFAULT_NUMBER_OF_THREADS = 8;
    private static final int SHUTDOWN_TIMEOUT_IN_SECONDS = 60;

    private ExecutorService taskExecutor;
    private CompletionService<ObjectImportContext> objectImportCompletionService;
    private CompletionService<LinkImportContext> linkImportCompletionService;
    private ImportContext importContext;
    private int number = 0;

    @Autowired
    private ObjectFactory<ObjectImportThread> objectImportThreadFactory;

    @Autowired
    private ObjectFactory<LinkImportThread> linkImportThreadFactory;

    /**
     * (non-Javadoc)
     * @see org.v2020.service.ie.IVnaImport#importVna(byte[])
     */
    @Override
    public void importVna(byte[] vnaFileData) {
        taskExecutor = createExecutor();
        objectImportCompletionService = new ExecutorCompletionService<ObjectImportContext>(taskExecutor);
        linkImportCompletionService = new ExecutorCompletionService<LinkImportContext>(taskExecutor);
        importContext = new ImportContext();
        try {
            Vna vna = new Vna(vnaFileData);
            List<SyncObject> syncObjectList = getSyncObjectList(vna);
            List<MapObjectType> mapObjectTypeList = getMapObjectTypeList(vna);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Starting import of objects...");
            }
            importObjectList(null, syncObjectList, mapObjectTypeList);
            if (LOG.isDebugEnabled()) {
                LOG.debug(number + " objects imported.");
            }
            List<SyncLink> syncLinkList = getSyncLinkList(vna);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Number of links: " + syncLinkList.size() + ", starting import...");
            }
            importLinkList(syncLinkList);
        } catch (Exception e) {
            LOG.error("Error while importing VNA.", e);
        } finally {
            shutdownAndAwaitTermination(taskExecutor);
        }
    }

    private void importObjectList(Node parent, List<SyncObject> syncObjectList,
            List<MapObjectType> mapObjectTypeList) throws InterruptedException, ExecutionException {
        if (syncObjectList != null) {
            for (SyncObject syncObject : syncObjectList) {
                ObjectImportThread importThread = objectImportThreadFactory.getObject();
                importThread.setContext(new ObjectImportContext(parent, syncObject, mapObjectTypeList));
                objectImportCompletionService.submit(importThread);
            }
            waitForObjectResults(syncObjectList.size());
        }
    }

    private void waitForObjectResults(int n) throws InterruptedException, ExecutionException {
        for (int i = 0; i < n; ++i) {
            ObjectImportContext objectContext = objectImportCompletionService.take().get();
            importContext.addObject(objectContext);
            if (objectContext != null) {
                importObjectList(objectContext.getNode(), objectContext.getSyncObject().getChildren(),
                        objectContext.getMapObjectTypeList());
            }
        }
        number += n;
    }

    private void importLinkList(List<SyncLink> syncLinkList) throws InterruptedException, ExecutionException {
        if (syncLinkList != null) {
            for (SyncLink syncLink : syncLinkList) {
                LinkImportThread importThread = linkImportThreadFactory.getObject();
                importThread.setContext(createImportContext(syncLink));
                linkImportCompletionService.submit(importThread);
            }
            waitForLinkResults(syncLinkList.size());
        }
    }

    private void waitForLinkResults(int n) throws InterruptedException, ExecutionException {
        for (int i = 0; i < n; ++i) {
            linkImportCompletionService.take().get();
        }
    }

    private LinkImportContext createImportContext(SyncLink syncLink) {
        Long startId = importContext.getDbId(syncLink.getDependant());
        Long endId = importContext.getDbId(syncLink.getDependency());
        LinkImportContext context = new LinkImportContext(startId, endId, syncLink.getRelationId());
        context.setComment(syncLink.getComment());
        return context;
    }

    private List<SyncObject> getSyncObjectList(Vna vna) {
        if (vna.getXml() != null && vna.getXml().getSyncData() != null
                && vna.getXml().getSyncData().getSyncObject() != null) {
            return vna.getXml().getSyncData().getSyncObject();
        } else {
            return Collections.emptyList();
        }
    }

    private List<SyncLink> getSyncLinkList(Vna vna) {
        if (vna.getXml() != null && vna.getXml().getSyncData() != null
                && vna.getXml().getSyncData().getSyncLink() != null) {
            return vna.getXml().getSyncData().getSyncLink();
        } else {
            return Collections.emptyList();
        }
    }

    private List<MapObjectType> getMapObjectTypeList(Vna vna) {
        if (vna.getXml() != null && vna.getXml().getSyncMapping() != null
                && vna.getXml().getSyncMapping().getMapObjectType() != null) {
            return vna.getXml().getSyncMapping().getMapObjectType();
        } else {
            return Collections.emptyList();
        }
    }

    private ExecutorService createExecutor() {
        if (LOG.isInfoEnabled()) {
            LOG.info("Number of threads: " + getMaxNumberOfThreads());
        }
        return Executors.newFixedThreadPool(getMaxNumberOfThreads());
    }

    private void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown(); // Disable new tasks from being submitted
        try {
            // Wait a while for existing tasks to terminate
            if (!pool.awaitTermination(getShutdownTimeoutInSeconds(), TimeUnit.SECONDS)) {
                pool.shutdownNow(); // Cancel currently executing tasks
                // Wait a while for tasks to respond to being cancelled
                if (!pool.awaitTermination(getShutdownTimeoutInSeconds(), TimeUnit.SECONDS))
                    LOG.error("Thread pool did not terminate", pool);
            }
        } catch (InterruptedException ie) {
            // (Re-)Cancel if current thread also interrupted
            pool.shutdownNow();
            // Preserve interrupt status
            Thread.currentThread().interrupt();
        }
    }

    private int getMaxNumberOfThreads() {
        return DEFAULT_NUMBER_OF_THREADS;
    }

    private int getShutdownTimeoutInSeconds() {
        return SHUTDOWN_TIMEOUT_IN_SECONDS;
    }

}