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.service;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.Serializable;
024import java.text.ParseException;
025import java.util.ArrayList;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.dom4j.Document;
033import org.dom4j.DocumentException;
034import org.dom4j.DocumentHelper;
035import org.dom4j.tree.DefaultElement;
036import org.jaxen.JaxenException;
037import org.jaxen.XPath;
038import org.jaxen.dom4j.Dom4jXPath;
039import org.nuxeo.common.utils.FileUtils;
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<String, Serializable>();
078
079        if (mappingDesc == null) {
080            return null;
081        }
082
083        String xmlData = FileUtils.readFile(xmlFile);
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            try {
096                XPath xpath = new Dom4jXPath(fieldMap.getSourceXPath());
097                nodes = xpath.selectNodes(xmlDoc);
098            } catch (JaxenException e) {
099                throw new IOException(e);
100            }
101            if (nodes.size() == 1) {
102                DefaultElement elem = (DefaultElement) nodes.get(0);
103                String value = null;
104                if ("TEXT".equals(fieldMap.getSourceAttribute())) {
105                    value = elem.getText();
106                } else {
107                    value = elem.attribute(fieldMap.getSourceAttribute()).getValue();
108                }
109
110                String target = fieldMap.getTargetXPath();
111                if ("string".equalsIgnoreCase(fieldMap.getTargetType())) {
112                    data.put(target, value);
113                    continue;
114                } else if ("integer".equalsIgnoreCase(fieldMap.getTargetType())) {
115                    data.put(target, Integer.parseInt(value));
116                    continue;
117                } else if ("double".equalsIgnoreCase(fieldMap.getTargetType())) {
118                    data.put(target, Double.parseDouble(value));
119                    continue;
120                } else if ("date".equalsIgnoreCase(fieldMap.getTargetType())) {
121                    try {
122                        data.put(target, fieldMap.getDateFormat().parse(value));
123                    } catch (ParseException e) {
124                        throw new IOException(e);
125                    }
126                    continue;
127                } else if ("boolean".equalsIgnoreCase(fieldMap.getTargetType())) {
128                    data.put(target, Boolean.parseBoolean(value));
129                    continue;
130                }
131                log.error("Unknown target type, please look the scan importer configuration: "
132                        + fieldMap.getTargetType());
133            }
134            log.error("Mulliple or no element(s) found for: " + fieldMap.sourceXPath + " for "
135                    + xmlFile.getAbsolutePath());
136
137        }
138
139        List<Blob> blobs = new ArrayList<Blob>();
140
141        for (ScanFileBlobMapping blobMap : mappingDesc.getBlobMappings()) {
142            List<?> nodes;
143            try {
144                XPath xpath = new Dom4jXPath(blobMap.getSourceXPath());
145                nodes = xpath.selectNodes(xmlDoc);
146            } catch (JaxenException e) {
147                throw new IOException(e);
148            }
149            for (Object node : nodes) {
150                DefaultElement elem = (DefaultElement) node;
151                String filePath = elem.attributeValue(blobMap.getSourcePathAttribute());
152                String fileName = elem.attributeValue(blobMap.getSourceFilenameAttribute());
153
154                // Mainly for tests
155                if (filePath.startsWith("$TMP")) {
156                    filePath = filePath.replace("$TMP", Framework.getProperty("nuxeo.import.tmpdir"));
157                }
158
159                File file = new File(filePath);
160                if (file.exists()) {
161                    Blob blob = Blobs.createBlob(file);
162                    if (fileName != null) {
163                        blob.setFilename(fileName);
164                    } else {
165                        blob.setFilename(file.getName());
166                    }
167                    String target = blobMap.getTargetXPath();
168                    if (target == null) {
169                        blobs.add(blob);
170                    } else {
171                        data.put(target, (Serializable) blob);
172                    }
173                } else {
174                    log.error("File " + file.getAbsolutePath() + " is referenced by " + xmlFile.getAbsolutePath()
175                            + " but was not found");
176                }
177            }
178        }
179
180        String targetType = getTargetLeafType();
181        DocumentTypeMapper mapper = mappingDesc.getTargetLeafTypeMapper();
182        if (mapper != null) {
183            targetType = mapper.getTargetDocumentType(xmlDoc, xmlFile);
184        }
185        ScanFileBlobHolder bh = new ScanFileBlobHolder(blobs, data, targetType);
186        return bh;
187    }
188
189    public ScanFileMappingDescriptor getMappingDesc() {
190        return mappingDesc;
191    }
192
193    @Override
194    public String getTargetContainerType() {
195        if (mappingDesc == null) {
196            return ScanFileMappingDescriptor.DEFAULT_CONTAINER_TYPE;
197        }
198        return mappingDesc.getTargetContainerType();
199    }
200
201    @Override
202    public String getTargetLeafType() {
203        if (mappingDesc == null) {
204            return ScanFileMappingDescriptor.DEFAULT_LEAF_TYPE;
205        }
206        return mappingDesc.getTargetLeafType();
207    }
208
209    @Override
210    public ImporterConfig getImporterConfig() {
211        return config;
212    }
213}