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.text.ParseException;
027import java.util.ArrayList;
028import java.util.HashMap;
029import java.util.List;
030import java.util.Map;
031
032import org.apache.commons.io.FileUtils;
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.dom4j.Document;
036import org.dom4j.DocumentException;
037import org.dom4j.DocumentHelper;
038import org.dom4j.tree.DefaultElement;
039import org.jaxen.JaxenException;
040import org.jaxen.XPath;
041import org.jaxen.dom4j.Dom4jXPath;
042import org.nuxeo.ecm.core.api.Blob;
043import org.nuxeo.ecm.core.api.Blobs;
044import org.nuxeo.ecm.platform.scanimporter.processor.DocumentTypeMapper;
045import org.nuxeo.runtime.api.Framework;
046import org.nuxeo.runtime.model.ComponentInstance;
047import org.nuxeo.runtime.model.DefaultComponent;
048
049/**
050 * Component to provide service logic : - meta-data parsing - configuration management - extension points
051 *
052 * @author Thierry Delprat
053 */
054public class ScannedFileMapperComponent extends DefaultComponent implements ScannedFileMapperService {
055
056    private static final Log log = LogFactory.getLog(ScannedFileMapperComponent.class);
057
058    public static final String MAPPING_EP = "mapping";
059
060    public static final String CONFIG_EP = "config";
061
062    protected ScanFileMappingDescriptor mappingDesc = null;
063
064    protected ImporterConfig config = null;
065
066    @Override
067    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
068
069        if (MAPPING_EP.equals(extensionPoint)) {
070            mappingDesc = (ScanFileMappingDescriptor) contribution;
071        } else if (CONFIG_EP.equals(extensionPoint)) {
072            config = (ImporterConfig) contribution;
073        }
074    }
075
076    @Override
077    public ScanFileBlobHolder parseMetaData(File xmlFile) throws IOException {
078
079        Map<String, Serializable> data = new HashMap<String, Serializable>();
080
081        if (mappingDesc == null) {
082            return null;
083        }
084
085        String xmlData = FileUtils.readFileToString(xmlFile);
086
087        Document xmlDoc;
088        try {
089            xmlDoc = DocumentHelper.parseText(xmlData);
090        } catch (DocumentException e) {
091            throw new IOException(e);
092        }
093
094        for (ScanFileFieldMapping fieldMap : mappingDesc.getFieldMappings()) {
095
096            List<?> nodes;
097            try {
098                XPath xpath = new Dom4jXPath(fieldMap.getSourceXPath());
099                nodes = xpath.selectNodes(xmlDoc);
100            } catch (JaxenException e) {
101                throw new IOException(e);
102            }
103            if (nodes.size() == 1) {
104                DefaultElement elem = (DefaultElement) nodes.get(0);
105                String value = null;
106                if ("TEXT".equals(fieldMap.getSourceAttribute())) {
107                    value = elem.getText();
108                } else {
109                    value = elem.attribute(fieldMap.getSourceAttribute()).getValue();
110                }
111
112                String target = fieldMap.getTargetXPath();
113                if ("string".equalsIgnoreCase(fieldMap.getTargetType())) {
114                    data.put(target, value);
115                    continue;
116                } else if ("integer".equalsIgnoreCase(fieldMap.getTargetType())) {
117                    data.put(target, Integer.parseInt(value));
118                    continue;
119                } else if ("double".equalsIgnoreCase(fieldMap.getTargetType())) {
120                    data.put(target, Double.parseDouble(value));
121                    continue;
122                } else if ("date".equalsIgnoreCase(fieldMap.getTargetType())) {
123                    try {
124                        data.put(target, fieldMap.getDateFormat().parse(value));
125                    } catch (ParseException e) {
126                        throw new IOException(e);
127                    }
128                    continue;
129                } else if ("boolean".equalsIgnoreCase(fieldMap.getTargetType())) {
130                    data.put(target, Boolean.parseBoolean(value));
131                    continue;
132                }
133                log.error("Unknown target type, please look the scan importer configuration: "
134                        + fieldMap.getTargetType());
135            }
136            log.error("Mulliple or no element(s) found for: " + fieldMap.sourceXPath + " for "
137                    + xmlFile.getAbsolutePath());
138
139        }
140
141        List<Blob> blobs = new ArrayList<Blob>();
142
143        for (ScanFileBlobMapping blobMap : mappingDesc.getBlobMappings()) {
144            List<?> nodes;
145            try {
146                XPath xpath = new Dom4jXPath(blobMap.getSourceXPath());
147                nodes = xpath.selectNodes(xmlDoc);
148            } catch (JaxenException e) {
149                throw new IOException(e);
150            }
151            for (Object node : nodes) {
152                DefaultElement elem = (DefaultElement) node;
153                String filePath = elem.attributeValue(blobMap.getSourcePathAttribute());
154                String fileName = elem.attributeValue(blobMap.getSourceFilenameAttribute());
155
156                // Mainly for tests
157                if (filePath.startsWith("$TMP")) {
158                    filePath = filePath.replace("$TMP", Framework.getProperty("nuxeo.import.tmpdir"));
159                }
160
161                File file = new File(filePath);
162                if (file.exists()) {
163                    Blob blob = Blobs.createBlob(file);
164                    if (fileName != null) {
165                        blob.setFilename(fileName);
166                    } else {
167                        blob.setFilename(file.getName());
168                    }
169                    String target = blobMap.getTargetXPath();
170                    if (target == null) {
171                        blobs.add(blob);
172                    } else {
173                        data.put(target, (Serializable) blob);
174                    }
175                } else {
176                    log.error("File " + file.getAbsolutePath() + " is referenced by " + xmlFile.getAbsolutePath()
177                            + " but was not found");
178                }
179            }
180        }
181
182        String targetType = getTargetLeafType();
183        DocumentTypeMapper mapper = mappingDesc.getTargetLeafTypeMapper();
184        if (mapper != null) {
185            targetType = mapper.getTargetDocumentType(xmlDoc, xmlFile);
186        }
187        ScanFileBlobHolder bh = new ScanFileBlobHolder(blobs, data, targetType);
188        return bh;
189    }
190
191    public ScanFileMappingDescriptor getMappingDesc() {
192        return mappingDesc;
193    }
194
195    @Override
196    public String getTargetContainerType() {
197        if (mappingDesc == null) {
198            return ScanFileMappingDescriptor.DEFAULT_CONTAINER_TYPE;
199        }
200        return mappingDesc.getTargetContainerType();
201    }
202
203    @Override
204    public String getTargetLeafType() {
205        if (mappingDesc == null) {
206            return ScanFileMappingDescriptor.DEFAULT_LEAF_TYPE;
207        }
208        return mappingDesc.getTargetLeafType();
209    }
210
211    @Override
212    public ImporterConfig getImporterConfig() {
213        return config;
214    }
215}