001/*
002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021package org.nuxeo.ecm.platform.scanimporter.service;
022
023import java.io.File;
024import java.io.IOException;
025import java.io.Serializable;
026import java.nio.charset.StandardCharsets;
027import java.text.ParseException;
028import java.util.ArrayList;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033import org.apache.commons.io.FileUtils;
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.dom4j.Document;
037import org.dom4j.DocumentException;
038import org.dom4j.DocumentHelper;
039import org.dom4j.tree.DefaultElement;
040import org.nuxeo.ecm.core.api.Blob;
041import org.nuxeo.ecm.core.api.Blobs;
042import org.nuxeo.ecm.platform.scanimporter.processor.DocumentTypeMapper;
043import org.nuxeo.runtime.api.Framework;
044import org.nuxeo.runtime.model.ComponentInstance;
045import org.nuxeo.runtime.model.DefaultComponent;
046
047/**
048 * Component to provide service logic : - meta-data parsing - configuration management - extension points
049 *
050 * @author Thierry Delprat
051 */
052public class ScannedFileMapperComponent extends DefaultComponent implements ScannedFileMapperService {
053
054    private static final Log log = LogFactory.getLog(ScannedFileMapperComponent.class);
055
056    public static final String MAPPING_EP = "mapping";
057
058    public static final String CONFIG_EP = "config";
059
060    protected ScanFileMappingDescriptor mappingDesc = null;
061
062    protected ImporterConfig config = null;
063
064    @Override
065    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
066
067        if (MAPPING_EP.equals(extensionPoint)) {
068            mappingDesc = (ScanFileMappingDescriptor) contribution;
069        } else if (CONFIG_EP.equals(extensionPoint)) {
070            config = (ImporterConfig) contribution;
071        }
072    }
073
074    @Override
075    public ScanFileBlobHolder parseMetaData(File xmlFile) throws IOException {
076
077        Map<String, Serializable> data = new HashMap<>();
078
079        if (mappingDesc == null) {
080            return null;
081        }
082
083        String xmlData = FileUtils.readFileToString(xmlFile, StandardCharsets.UTF_8);
084
085        Document xmlDoc;
086        try {
087            xmlDoc = DocumentHelper.parseText(xmlData);
088        } catch (DocumentException e) {
089            throw new IOException(e);
090        }
091
092        for (ScanFileFieldMapping fieldMap : mappingDesc.getFieldMappings()) {
093
094            List<?> nodes;
095            nodes = xmlDoc.selectNodes(fieldMap.getSourceXPath());
096            if (nodes.size() == 1) {
097                DefaultElement elem = (DefaultElement) nodes.get(0);
098                String value;
099                if ("TEXT".equals(fieldMap.getSourceAttribute())) {
100                    value = elem.getText();
101                } else {
102                    value = elem.attribute(fieldMap.getSourceAttribute()).getValue();
103                }
104
105                String target = fieldMap.getTargetXPath();
106                if ("string".equalsIgnoreCase(fieldMap.getTargetType())) {
107                    data.put(target, value);
108                    continue;
109                } else if ("integer".equalsIgnoreCase(fieldMap.getTargetType())) {
110                    data.put(target, Integer.valueOf(value));
111                    continue;
112                } else if ("double".equalsIgnoreCase(fieldMap.getTargetType())) {
113                    data.put(target, Double.valueOf(value));
114                    continue;
115                } else if ("date".equalsIgnoreCase(fieldMap.getTargetType())) {
116                    try {
117                        data.put(target, fieldMap.getDateFormat().parse(value));
118                    } catch (ParseException e) {
119                        throw new IOException(e);
120                    }
121                    continue;
122                } else if ("boolean".equalsIgnoreCase(fieldMap.getTargetType())) {
123                    data.put(target, Boolean.valueOf(value));
124                    continue;
125                }
126                log.error("Unknown target type, please look the scan importer configuration: "
127                        + fieldMap.getTargetType());
128            }
129            log.error("Mulliple or no element(s) found for: " + fieldMap.sourceXPath + " for "
130                    + xmlFile.getAbsolutePath());
131
132        }
133
134        List<Blob> blobs = new ArrayList<>();
135
136        for (ScanFileBlobMapping blobMap : mappingDesc.getBlobMappings()) {
137            List<?> nodes;
138            nodes = xmlDoc.selectNodes(blobMap.getSourceXPath());
139            for (Object node : nodes) {
140                DefaultElement elem = (DefaultElement) node;
141                String filePath = elem.attributeValue(blobMap.getSourcePathAttribute());
142                String fileName = elem.attributeValue(blobMap.getSourceFilenameAttribute());
143
144                // Mainly for tests
145                if (filePath.startsWith("$TMP")) {
146                    filePath = filePath.replace("$TMP", Framework.getProperty("nuxeo.import.tmpdir"));
147                }
148
149                File file = new File(filePath);
150                if (file.exists()) {
151                    Blob blob = Blobs.createBlob(file);
152                    if (fileName != null) {
153                        blob.setFilename(fileName);
154                    } else {
155                        blob.setFilename(file.getName());
156                    }
157                    String target = blobMap.getTargetXPath();
158                    if (target == null) {
159                        blobs.add(blob);
160                    } else {
161                        data.put(target, (Serializable) blob);
162                    }
163                } else {
164                    log.error("File " + file.getAbsolutePath() + " is referenced by " + xmlFile.getAbsolutePath()
165                            + " but was not found");
166                }
167            }
168        }
169
170        String targetType = getTargetLeafType();
171        DocumentTypeMapper mapper = mappingDesc.getTargetLeafTypeMapper();
172        if (mapper != null) {
173            targetType = mapper.getTargetDocumentType(xmlDoc, xmlFile);
174        }
175        return new ScanFileBlobHolder(blobs, data, targetType);
176    }
177
178    public ScanFileMappingDescriptor getMappingDesc() {
179        return mappingDesc;
180    }
181
182    @Override
183    public String getTargetContainerType() {
184        if (mappingDesc == null) {
185            return ScanFileMappingDescriptor.DEFAULT_CONTAINER_TYPE;
186        }
187        return mappingDesc.getTargetContainerType();
188    }
189
190    @Override
191    public String getTargetLeafType() {
192        if (mappingDesc == null) {
193            return ScanFileMappingDescriptor.DEFAULT_LEAF_TYPE;
194        }
195        return mappingDesc.getTargetLeafType();
196    }
197
198    @Override
199    public ImporterConfig getImporterConfig() {
200        return config;
201    }
202}