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