001/*
002 * (C) Copyright 2006-2012 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id$
018 */
019package org.nuxeo.ecm.platform.scanimporter.processor;
020
021import java.io.File;
022import java.io.IOException;
023import java.lang.reflect.Constructor;
024import java.nio.file.Files;
025import java.nio.file.Path;
026import java.util.ArrayList;
027import java.util.List;
028import java.util.concurrent.locks.ReentrantReadWriteLock;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.nuxeo.ecm.core.api.NuxeoException;
033import org.nuxeo.ecm.platform.importer.base.GenericMultiThreadedImporter;
034import org.nuxeo.ecm.platform.importer.factories.ImporterDocumentModelFactory;
035import org.nuxeo.ecm.platform.importer.log.BasicLogger;
036import org.nuxeo.ecm.platform.importer.service.DefaultImporterService;
037import org.nuxeo.ecm.platform.importer.source.FileSourceNode;
038import org.nuxeo.ecm.platform.importer.source.SourceNode;
039import org.nuxeo.ecm.platform.scanimporter.service.ImporterConfig;
040import org.nuxeo.ecm.platform.scanimporter.service.ScannedFileMapperService;
041import org.nuxeo.runtime.api.Framework;
042
043/**
044 * Setup the importer with the rights factories
045 *
046 * @author Thierry Delprat
047 */
048public class ScannedFileImporter {
049
050    private static final Log log = LogFactory.getLog(ScannedFileImporter.class);
051
052    protected static List<String> processedDescriptors;
053
054    protected static ReentrantReadWriteLock processedLock = new ReentrantReadWriteLock();
055
056    public ScannedFileImporter() {
057        processedDescriptors = new ArrayList<String>();
058    }
059
060    public static void addProcessedDescriptor(String fileDesc) {
061        processedLock.writeLock().lock();
062        try {
063            processedDescriptors.add(fileDesc);
064            if (processedDescriptors.size() % 100 == 0) {
065                doCleanUp();
066            }
067        } finally {
068            processedLock.writeLock().unlock();
069        }
070    }
071
072    protected static void doCleanUp() {
073
074        ScannedFileMapperService sfms = Framework.getLocalService(ScannedFileMapperService.class);
075        ImporterConfig config = sfms.getImporterConfig();
076        File outDir = null;
077
078        if (config != null) {
079            String outPath = config.getProcessedPath();
080            if (outPath != null) {
081                outDir = new File(outPath);
082                if (!outDir.exists()) {
083                    outDir = null;
084                }
085            }
086        }
087        for (String fileDesc : processedDescriptors) {
088            File file = new File(fileDesc);
089            if (file.exists()) {
090                if (outDir == null) {
091                    file.delete();
092                } else {
093                    Path source = file.toPath();
094                    Path target = outDir.toPath().resolve(file.getName());
095                    try {
096                        Files.move(source, target);
097                    } catch (IOException e) {
098                        log.error("An exception occured while moving " + source.getFileName(), e);
099                    }
100                }
101            }
102        }
103        processedDescriptors = new ArrayList<String>();
104    }
105
106    public void doImport() {
107
108        ScannedFileMapperService sfms = Framework.getLocalService(ScannedFileMapperService.class);
109
110        ImporterConfig config = sfms.getImporterConfig();
111        if (config == null) {
112            log.error("No configuration can be found, exit importer");
113            return;
114        }
115        File folder = new File(config.getSourcePath());
116
117        doImport(folder, config);
118    }
119
120    public void doImport(File folder, ImporterConfig config) {
121
122        if (folder == null || !folder.exists()) {
123            throw new NuxeoException("Unable to access source folder " + folder);
124        }
125        if (config.getTargetPath() == null) {
126            throw new NuxeoException("target path must be set");
127        }
128
129        if (folder.listFiles().length == 0) {
130            log.info("Nothing to import exiting");
131            return;
132        }
133
134        log.info("Starting import process on path " + config.getTargetPath() + " from source "
135                + folder.getAbsolutePath());
136        SourceNode src = initSourceNode(folder);
137
138        ScanedFileSourceNode.useXMLMapping = config.useXMLMapping();
139        GenericMultiThreadedImporter importer = new GenericMultiThreadedImporter(src, config.getTargetPath(),
140                !config.isCreateInitialFolder(), config.getBatchSize(), config.getNbThreads(), new BasicLogger(log));
141
142        ImporterDocumentModelFactory factory = initDocumentModelFactory(config);
143        importer.setFactory(factory);
144        importer.setTransactionTimeout(config.getTransactionTimeout());
145        importer.run();
146
147        log.info("Fininish moving files");
148        doCleanUp();
149
150        log.info("Ending import process");
151    }
152
153    /**
154     * @since 5.7.3
155     */
156    private ImporterDocumentModelFactory initDocumentModelFactory(ImporterConfig config) {
157        Class<? extends ImporterDocumentModelFactory> factoryClass = Framework.getLocalService(
158                DefaultImporterService.class).getDocModelFactoryClass();
159        // Class<? extends DefaultDocumentModelFactory> factoryClass = ScanedFileFactory.class;
160        Constructor<? extends ImporterDocumentModelFactory> cst = null;
161
162        try {
163            try {
164                cst = factoryClass.getConstructor(ImporterConfig.class);
165                return cst.newInstance(config);
166            } catch (NoSuchMethodException e) {
167                return factoryClass.newInstance();
168            }
169        } catch (ReflectiveOperationException e) {
170            throw new NuxeoException(e);
171        }
172    }
173
174    /**
175     * @throws Exception
176     * @since 5.7.3
177     */
178    private SourceNode initSourceNode(File file) {
179        Class<? extends SourceNode> srcClass = Framework.getLocalService(DefaultImporterService.class).getSourceNodeClass();
180        // Class<? extends SourceNode> srcClass = ScanedFileSourceNode.class;
181        if (!FileSourceNode.class.isAssignableFrom(srcClass)) {
182            throw new NuxeoException("Waiting source node extending FileSourceNode for Scan Importer");
183        }
184        try {
185            return srcClass.getConstructor(File.class).newInstance(file);
186        } catch (ReflectiveOperationException e) {
187            throw new NuxeoException(e);
188        }
189    }
190
191}