chemistry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1305762 [1/2] - in /chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client: ./ src/main/java/org/apache/chemistry/opencmis/client/filecopy/ src/main/java/org/apache/chemistry/opencmis/client/main/ src/main/java/org...
Date Tue, 27 Mar 2012 07:43:33 GMT
Author: jens
Date: Tue Mar 27 07:43:31 2012
New Revision: 1305762

URL: http://svn.apache.org/viewvc?rev=1305762&view=rev
Log:
Enhance command line client in test-util to upload local files with metadata extraction [CMIS-515]

Added:
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/filecopy/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/filecopy/FileCopier.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/AbstractPropertyMapper.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/Configurator.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/MapperException.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapper.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperExif.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperTika.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/AbstractMetadataParser.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParser.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserExif.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserTika.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/resources/mapping.properties
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/apache/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/apache/chemistry/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/apache/chemistry/opencmis/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/apache/chemistry/opencmis/client/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/apache/chemistry/opencmis/client/mapper/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/java/org/apache/chemistry/opencmis/client/mapper/ConfiguratorTest.java
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/AudioPropertyDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/AudioTypeDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/EmailPropertyDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/EmailTypeDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/ExifPropertyDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/ExifTypeDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/OfficePropertyDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/OfficeTypeDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/PDFPropertyDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/PDFTypeDefinitions.txt
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/test/resources/TypesXmlGenerator.groovy
Modified:
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/pom.xml
    chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/main/ObjGenApp.java

Modified: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/pom.xml
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/pom.xml?rev=1305762&r1=1305761&r2=1305762&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/pom.xml (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/pom.xml Tue Mar 27 07:43:31 2012
@@ -59,13 +59,11 @@
             <artifactId>chemistry-opencmis-test-util</artifactId>
             <version>${project.version}</version>
         </dependency>
-        <!--
 		<dependency>
             <groupId>org.apache.tika</groupId>
             <artifactId>tika-parsers</artifactId>
             <version>1.0</version>
         </dependency>
-        -->
         <dependency>
             <groupId>net.sf.jopt-simple</groupId>
             <artifactId>jopt-simple</artifactId>

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/filecopy/FileCopier.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/filecopy/FileCopier.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/filecopy/FileCopier.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/filecopy/FileCopier.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.filecopy;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.api.Document;
+import org.apache.chemistry.opencmis.client.api.Folder;
+import org.apache.chemistry.opencmis.client.api.ObjectId;
+import org.apache.chemistry.opencmis.client.api.Session;
+import org.apache.chemistry.opencmis.client.api.SessionFactory;
+import org.apache.chemistry.opencmis.client.mapper.Configurator;
+import org.apache.chemistry.opencmis.client.mapper.MapperException;
+import org.apache.chemistry.opencmis.client.mapper.PropertyMapper;
+import org.apache.chemistry.opencmis.client.parser.MetadataParser;
+import org.apache.chemistry.opencmis.client.parser.MetadataParserTika;
+import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.data.ContentStream;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.enums.VersioningState;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tika.Tika;
+    
+public class FileCopier {
+    
+    private static final Log LOG = LogFactory.getLog(FileCopier.class.getName());
+    // initialize configurator to get parsers and property mappings
+    private static final Configurator CFG = Configurator.getInstance(); 
+    
+    private Session session;
+    
+    public FileCopier() {
+    }
+    
+    public void connect(Map<String, String> parameters) {
+        System.out.println("Connecting to a repository ...");
+
+        // Create a SessionFactory and set up the SessionParameter map
+        SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
+
+        session = sessionFactory.createSession(parameters);
+
+        LOG.debug("Got a connection to repository.");
+    }
+        
+    public void copyRecursive(String folderName, String folderId) {
+
+        try {
+            File fileOrDir = new File(folderName);
+            if (fileOrDir.isDirectory()) {
+                String newFolderId = createFolderInRepository(fileOrDir.getAbsolutePath(), folderId);
+                File[] children = fileOrDir.listFiles();
+                for (File file: children) {
+                    if (!file.getName().equals(".") && !file.getName().equals("..")) {
+                        copyRecursive(file.getAbsolutePath(), newFolderId);
+                    }
+                }
+            } else {
+                copyFileToRepository(fileOrDir.getAbsolutePath(), folderId);
+            }            
+        } catch (Exception e) {
+            LOG.error(e);
+        } finally {  
+        }
+    }
+    
+    private String copyFileToRepository(String fileName, String folderId) {
+        LOG.debug("uploading file " + fileName);
+        FileInputStream is = null;
+        Map<String, Object> properties = new HashMap<String, Object>();
+        Folder parentFolder;
+        String id = null;
+        
+        if (null == folderId)
+            parentFolder = session.getRootFolder();
+        else
+            parentFolder = (Folder) session.getObject(folderId);
+        
+        try {
+            File f = new File(fileName);
+            Tika tika = new Tika();     
+            String mimeType = tika.detect(f);
+            LOG.info("Detected MIME type: "+ mimeType);
+            
+            // extract metadata: first get a parser
+            MetadataParser parser = CFG.getParser(mimeType);
+            if (null == parser) {
+                properties.put(PropertyIds.NAME, f.getName());
+                properties.put(PropertyIds.OBJECT_TYPE_ID, CFG.getDefaultDocumentType());
+            } else {
+                parser.reset();
+                PropertyMapper mapper = CFG.getPropertyMapper(mimeType);
+                if (null == mapper)
+                    throw new MapperException("Unknown mime type (no configuration): " + mimeType);
+                String typeId = mapper.getMappedTypeId();
+                if (null == typeId)
+                    throw new MapperException("No CMIS type configured for mime type" + mimeType);
+                TypeDefinition td = session.getTypeDefinition(typeId);
+                if (null == td)
+                    throw new MapperException("CMIS type " + typeId + " does not exist on server.");
+
+                LOG.info("Detected MIME type: "+ mimeType + " is mapped to CMIS type id: " + td.getId());
+                parser.extractMetadata(f, td);
+                properties = parser.getCmisProperties();
+            }
+                        
+            // check if there is an overridden content type configured
+            int posLastDot = f.getName().indexOf('.');
+            String ext = posLastDot < 0 ? null : f.getName().substring(posLastDot+1, f.getName().length());
+            String overridden = null;
+            if (null != ext && (overridden = CFG.getContentType(ext)) != null)
+                mimeType = overridden;
+            long length = f.length();
+            
+            is = new FileInputStream(fileName);
+
+            ContentStream contentStream = session.getObjectFactory().createContentStream(fileName,
+                    length, mimeType, is);
+            if (!properties.containsKey(PropertyIds.NAME))
+                properties.put(PropertyIds.NAME, f.getName());
+            Document doc = parentFolder.createDocument(properties, contentStream, VersioningState.NONE);
+            id = doc.getId();
+            LOG.info("New document created with id: " + id + ", name: " +  properties.get(PropertyIds.NAME) + " in folder: " + parentFolder.getId());
+        } catch (Exception e) {
+            LOG.error("Failed to create CMIS document.", e);
+        } finally {
+            if (null != is) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    LOG.error(e);
+                }
+            }
+            LOG.debug("Conversion and transfer done.");    
+        }
+        return id;
+    }
+    
+    private  String createFolderInRepository(String fileName, String parentFolderId) {
+        Folder parentFolder;
+        String id = null;
+        if (null == parentFolderId)
+            parentFolder = session.getRootFolder();
+        else
+            parentFolder = (Folder) session.getObject(parentFolderId);
+        Map<String, Object> properties = new HashMap<String, Object>();
+        File f = new File(fileName);
+        properties.put(PropertyIds.NAME, f.getName());
+        properties.put(PropertyIds.OBJECT_TYPE_ID, CFG.getDefaultFolderType());
+        try {
+            Folder folder = parentFolder.createFolder(properties);
+            id = folder.getId();
+            LOG.debug("New folder created with id: " + folder.getId() + ", path: " + folder.getPaths().get(0));
+        } catch (Exception e) {
+            LOG.error("Failed to create CMIS document.", e);
+        } finally {
+        }
+        LOG.info("New folder created with id: " + id + ", name: " +  properties.get(PropertyIds.NAME) + " in parent folder: " + parentFolder.getId());
+        return id;
+    }
+    
+    public void listMetadata(String fileName) {
+        try {
+            File f = new File(fileName);
+            Tika tika = new Tika();     
+            String mimeType = tika.detect(f);
+            LOG.info("Detected MIME type: "+ mimeType);
+            
+            // extract metadata: first get a parser
+            MetadataParser parser = CFG.getParser(mimeType);
+            if (null == parser) {
+                LOG.warn("Unknown content type " + mimeType + " no metadata found, listing all tags found in file.");
+                MetadataParserTika mpt = new MetadataParserTika();
+                mpt.listMetadata(f);
+            } else {
+                PropertyMapper mapper = CFG.getPropertyMapper(mimeType);
+                if (null == mapper)
+                    throw new MapperException("Unknown mime type (no configuration): " + mimeType);
+                String typeId = mapper.getMappedTypeId();
+                if (null == typeId)
+                    throw new MapperException("No CMIS type configured for mime type" + mimeType);
+                
+                // Session available? if yes do conversion
+                TypeDefinition td = null;
+                if (null!= session) {
+                    session.getTypeDefinition(typeId);
+                    if (null == td)
+                        throw new MapperException("CMIS type " + typeId + " does not exist on server.");
+                }
+                LOG.info("Detected MIME type: "+ mimeType + " is mapped to CMIS type id: " + td.getId());
+                
+                parser.extractMetadata(f, td);
+                Map<String, Object> properties = parser.getCmisProperties();
+                for (String key : properties.keySet()) {
+                    LOG.info("Found metadata tag " + key + "mapped to " + properties.get(key));
+                }
+            }                        
+        } catch (Exception e) {
+            LOG.error("Failed to list metadata", e);
+        } finally {
+        }
+        LOG.debug("Conversion and transfer done.");            
+    }
+    
+    static public void main(String[] args) {
+        String fileName = args[0];
+        LOG.debug("extracting CMIS properties for file " + fileName);
+        try {
+            new FileCopier().listMetadata(fileName);            
+        } catch (Exception e) {
+            LOG.error(e);
+        } finally {
+        }
+        LOG.debug("Extraction done.");    
+    }
+}

Modified: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/main/ObjGenApp.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/main/ObjGenApp.java?rev=1305762&r1=1305761&r2=1305762&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/main/ObjGenApp.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/main/ObjGenApp.java Tue Mar 27 07:43:31 2012
@@ -33,6 +33,7 @@ import joptsimple.OptionSet;
 import joptsimple.OptionSpec;
 
 import org.apache.chemistry.opencmis.client.bindings.CmisBindingFactory;
+import org.apache.chemistry.opencmis.client.filecopy.FileCopier;
 import org.apache.chemistry.opencmis.commons.SessionParameter;
 import org.apache.chemistry.opencmis.commons.data.ContentStream;
 import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
@@ -209,6 +210,8 @@ public class ObjGenApp {
             createFiles(options);
         } else if (options.valueOf(fCmd).equals("CopyFiles")) {
             transferFiles(options);
+        } else if (options.valueOf(fCmd).equals("CopyFilesTest")) { // undocumented
+            transferFilesTest(options);
         } else {
             System.out.println("Unknown cmd: " + options.valueOf(fCmd));
             usage(parser);
@@ -542,11 +545,18 @@ public class ObjGenApp {
         String fileName = options.valueOf(fLocalFile);
         String dirName = options.valueOf(fLocalDir);
         String repoId = options.valueOf(fRepoId);
+        String folderId = options.valueOf(fRootFolder);
+        String name = fileName;
         
         if ((null == fileName || fileName.length() == 0) && (null == dirName || dirName.length() == 0)) {
             System.out.println("Error: You either have to provide a --file or a --dir option to copy file(s).");
             return;
         }
+        
+        // if no file name is provided there must be a directory
+        if (null == name || name.length() == 0)
+            name = dirName;
+        
         if (null == fRepoId || repoId.length() == 0) {
             System.out.println("Error: You have to provide a repository id");
             return;
@@ -555,13 +565,27 @@ public class ObjGenApp {
         System.out.println("Repository id is: " + repoId);
         System.out.println("Folder id used as root: " + options.valueOf(fRootFolder));
         
+        
         Map<String, String> parameters = getConnectionParameters(getBinding(), repoId);
-        System.out.println("TODO: Not implemented.");
-//        FileCopy fc = new FileCopy();
-//        fc.connect(parameters);
-//        fc.copyFileToRepository(fileName);
+        FileCopier fc = new FileCopier();
+        fc.connect(parameters);
+        fc.copyRecursive(name, folderId);
     }
         
+    private void transferFilesTest(OptionSet options) {
+        String fileName = options.valueOf(fLocalFile);
+        
+        if ((null == fileName || fileName.length() == 0)) {
+            System.out.println("Error: You either have to provide a --file option to test metadata extraction.");
+            return;
+        }
+        
+        System.out.println("Testing metadata extraction: ");
+        
+        FileCopier fc = new FileCopier();
+        fc.listMetadata(fileName);
+    }
+
     private Map<String, String> getConnectionParameters(String binding, String repoId) {
         Map<String, String> parameters = new HashMap<String, String>();
         parameters.put(SessionParameter.REPOSITORY_ID, repoId);

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/AbstractPropertyMapper.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/AbstractPropertyMapper.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/AbstractPropertyMapper.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/AbstractPropertyMapper.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,61 @@
+/*
+ * Li
+censed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.mapper;
+
+import java.util.Properties;
+
+public abstract class AbstractPropertyMapper implements PropertyMapper {
+    
+    private static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
+
+    protected String[] contentTypes;
+    protected String cmisTypeId;
+    protected String propPrefix;
+    protected String dateFormat = DEFAULT_DATE_FORMAT;    
+
+    public boolean initialize(String cfgPrefix, String typeKey, Properties properties) {
+        propPrefix = cfgPrefix + "." + typeKey;
+        cmisTypeId =   properties.getProperty(propPrefix + ".typeId");
+        String contentTypeEntry = properties.getProperty(propPrefix);
+         
+        contentTypes = contentTypeEntry.split("\\:");
+        for (int i=0; i<contentTypes.length; i++) {
+            contentTypes[i] = contentTypes[i].trim();
+        }
+
+        String df = properties.getProperty(propPrefix + ".dateFormat");
+        if (null!=df)
+            dateFormat = df;
+                
+        if (null == cmisTypeId) 
+            throw new MapperException("Missingt type id in properties: " + propPrefix + ".typeId");
+        
+        return true;
+    }
+
+    public String getMappedTypeId() {
+        return cmisTypeId;
+    }
+    
+    public String[] getContentTypes() {
+        return contentTypes;
+    }
+
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/Configurator.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/Configurator.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/Configurator.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/Configurator.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.mapper;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.chemistry.opencmis.client.parser.MetadataParser;
+import org.apache.chemistry.opencmis.client.parser.MetadataParserTika;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class Configurator {
+
+    private static final Log LOG = LogFactory.getLog(Configurator.class.getName());
+    
+    private static Configurator INSTANCE;
+    static final String PREFIX = "mapping.contentType";
+    
+    public static Configurator getInstance() {
+        if (null == INSTANCE)
+            INSTANCE = new Configurator();
+        return INSTANCE;
+    }
+    
+    private Properties properties;
+    private Map<String, PropertyMapper> contentTypeMapperMap  = new HashMap<String, PropertyMapper>();
+    private Map<String, MetadataParser> parserMap = new HashMap<String, MetadataParser>();
+    private String defaultDocumentType;
+    private String defaultFolderType;
+    
+    private Configurator() {     
+        loadProperties();
+        loadDefaults();
+        buildMapperMap();
+        createParsers();
+    }
+    
+    // just for unit tests
+    Configurator(Properties props) {
+//        contentTypeMapperMap = new HashMap<String, PropertyMapper>();
+        this.properties = props;
+    }
+    
+    
+    public PropertyMapper getPropertyMapper(String contentType) {
+        MetadataParser parser = getParser(contentType);
+        return parser.getMapper();
+    }
+    
+    public MetadataParser getParser(String contentType) {
+        MetadataParser parser = parserMap.get(contentType);
+        if (null == parser) {
+            // if not found try a more generic one
+            String genericContentType = contentType.substring(0, contentType.indexOf('/')) + "/*";
+            for (String key: parserMap.keySet()) {
+                if (key.equals(genericContentType))
+                    return parserMap.get(key);
+            }
+        }
+        return parser;
+        
+//        for (String contentType : contentTypes) {
+//            if (contentType.equals(mimeType))
+//                return cmisTypeId;
+//            boolean isStar = contentType.endsWith("/*");
+//            if (isStar) {
+//                String generalPartParam = mimeType.substring(0, mimeType.indexOf('/'));
+//                String generalPartCfg = contentType.substring(0, mimeType.indexOf('/'));
+//                if (generalPartParam.equals(generalPartCfg))
+//                    return cmisTypeId;
+//            }
+//        }
+//        return null;        
+    }
+
+    private void loadProperties() {
+        // Returns null on lookup failures:
+        InputStream in = Configurator.class.getResourceAsStream ("/mapping.properties");
+        if (in != null)
+        {
+            properties = new Properties();
+            try {
+                properties.load (in);
+            } catch (IOException e) {
+                LOG.error(e);
+                e.printStackTrace();
+                throw new MapperException("Could not load file mapping.properties as resource", e);
+            } 
+        }
+    }
+    
+    private void loadDefaults() {
+        defaultDocumentType = properties.getProperty(PREFIX + ".default.document");
+        if (null == defaultDocumentType)
+            defaultDocumentType = "cmis:document";
+        
+        defaultFolderType = properties.getProperty(PREFIX + ".default.folder");
+        if (null == defaultFolderType)
+            defaultFolderType = "cmis:folder";                
+    }
+    
+    public String getDefaultDocumentType() {
+        return defaultDocumentType;
+    }
+    
+    public String getDefaultFolderType() {
+        return defaultFolderType;
+    }
+
+    public final Properties getProperties() {
+        return properties;
+    }
+    
+    /**
+     * return an overridden MIME type from a file extension
+     * 
+     * @param fileExtension
+     *      enforced or content-type or null if none is set
+     */
+    public String getContentType(String fileExtension) {
+        return properties.getProperty(PREFIX+ ".forceContentType." + fileExtension, null);
+    }
+    
+    String[] getTypeKeys() {
+        String s = properties.getProperty(PREFIX + "s");
+        
+        if (null == s)
+            return null;
+        
+        String[] keys = s.split(",");
+        
+        for (int i=0; i<keys.length; i++)
+            keys[i] = keys[i].trim();
+        
+        return keys;
+    }
+    
+    void  buildMapperMap() {
+        
+        String[] typeKeys = getTypeKeys();
+        for (String typeKey : typeKeys) {
+            PropertyMapper mapper = loadMapperClass(typeKey);
+            String contentType = properties.getProperty(PREFIX + "." + typeKey);
+            if (null == contentType) 
+                throw new MapperException("Missingt content type in properties: " + PREFIX + "." + contentType);
+            boolean ok = mapper.initialize(PREFIX, typeKey, properties);
+
+            if (ok)
+                contentTypeMapperMap.put(typeKey, mapper);
+        }        
+    }
+    
+    void createParsers() {
+        String[] typeKeys = getTypeKeys();
+        for (String typeKey : typeKeys) {
+            MetadataParser parser = loadParserClass(typeKey);
+            String contentType = properties.getProperty(PREFIX + "." + typeKey);
+            if (null == contentType) 
+                throw new MapperException("Missing content type in properties: " + PREFIX + "." + contentType);
+            
+            PropertyMapper mapper = contentTypeMapperMap.get(typeKey);
+
+            parser.initialize(mapper, contentType);
+            String[] contentTypes = parser.getContentTypes();
+            for (String ct : contentTypes)
+                parserMap.put(ct, parser);
+        }                
+    }
+    
+    MetadataParser loadParserClass(String typeKey) {
+        String className = properties.getProperty(PREFIX + "." + typeKey + ".parserClass");
+        if (null == className) // use Tika as default parser if none is configured
+            className = MetadataParserTika.class.getName();
+//            throw new MapperException("Missing parser class in properties: " + PREFIX + "." + typeKey + ".parserClass");
+
+        Object obj = null;
+
+        try {
+            obj = Class.forName(className).newInstance();
+        } catch (InstantiationException e) {
+            LOG.error(e);
+            throw new MapperException(
+                    "Illegal class to load metadata parser, cannot instantiate " + className, e);
+        } catch (IllegalAccessException e) {
+            LOG.error(e);
+            throw new MapperException(
+                    "Illegal class to load metadata parser, cannot access " + className, e);
+        } catch (ClassNotFoundException e) {
+            LOG.error(e);
+            throw new MapperException(
+                    "Illegal class to load metadata parser, class not found: " + className, e);
+        }
+
+        if (obj instanceof MetadataParser) {
+            return (MetadataParser) obj;
+        } else {
+            throw new MapperException("Illegal class to create metadata parser: " + className + ", must implement MetadataParser interface.");
+        }
+    }
+
+    PropertyMapper loadMapperClass(String typeKey) {
+        String className = properties.getProperty(PREFIX + "." + typeKey + ".mapperClass");
+        if (null == className) 
+            className = PropertyMapperTika.class.getName();
+//            throw new MapperException("Missing property mapper in properties: " + PREFIX + "." + typeKey + ".mapperClass");
+
+        Object obj = null;
+
+        try {
+            obj = Class.forName(className).newInstance();
+        } catch (InstantiationException e) {
+            LOG.error(e);
+            throw new MapperException(
+                    "Illegal class to load mapping configuration, cannot instantiate " + className, e);
+        } catch (IllegalAccessException e) {
+            LOG.error(e);
+            throw new MapperException(
+                    "Illegal class to load mapping configuration, cannot access " + className, e);
+        } catch (ClassNotFoundException e) {
+            LOG.error(e);
+            throw new MapperException(
+                    "Illegal class to load mapping configuration, class not found: " + className, e);
+        }
+
+        if (obj instanceof PropertyMapper) {
+            return (PropertyMapper) obj;
+        } else {
+            throw new MapperException("Illegal class to create property mapper: " + className + ", must implement PropertyMapper interface.");
+        }
+    }
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/MapperException.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/MapperException.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/MapperException.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/MapperException.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.mapper;
+
+
+
+public class MapperException extends RuntimeException {
+    
+    private static final long serialVersionUID = 1L;
+
+    public MapperException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public MapperException(String message) {
+        super(message);
+    }
+
+
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapper.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapper.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapper.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapper.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.mapper;
+
+import java.util.Properties;
+
+import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
+
+/**
+ * A property mapper is a class being responsible to map a Content-Type (e.g. image/jpeg)
+ * to a CMIS type id and to map and convert properties. Extracted tags are mapped to 
+ * CMIS property ids and sometimes type conversion is required (e.g. a string to a date).
+ * Classes implementing this interface are not responsible for extracting the metadata 
+ * (see MetadataParser). It only reads a configuration and maps properties. The 
+ * Configurator will read the configuration properties and instantiate implementations 
+ * of this interface (one instance per CMIS type)
+ * 
+ * @author Jens
+ *
+ */
+public interface PropertyMapper {
+    
+    /**
+     * initialize a property mapper
+     * @param cfgPrefix
+     *      prefix for all configuration entries in properties file
+     * @param typeKey
+     *      type key in configuration used to identify this type
+     * @param properties
+     *      all properties read from resource mapping.properties
+     * @return
+     *      true, if processing should continue, false if not 
+     */
+    boolean initialize(String cfgPrefix, String typeKey, Properties properties);
+    
+    /**
+     * Reset all internal data to get ready for a new parsing process 
+     */
+    void reset();
+    
+    /**
+     * return the CMIS type id used for this mapper
+     * @return
+     *      CMIS type id to map this content type to or null if not mappable
+     */
+    String getMappedTypeId();
+    
+    /**
+     * return the CMIS property id for a found tag in a file
+     * @param key
+     *      tag (usually parsed from Tika) found in file
+     * @return
+     *      CMIS property this tag gets mapped to, null if not mapped
+     */
+    String getMappedPropertyId(String key);
+    
+    /**
+     * Convert a value parsed from the file to the type the corresponding property expects
+     * @param id
+     *      CMIS property id
+     * @param propertyType
+     *      property type from type definition
+     * @param strValue
+     *      value read from file (Tika always gives a string)
+     * @return
+     *      converted value conforming to the mapped property
+     */
+    Object convertValue(String id, PropertyDefinition<?> propDef, String strValue);
+
+    /**
+     * get all content types handled by this parser
+     * @return
+     *      array with content types
+     */
+    public String[] getContentTypes();
+
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperExif.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperExif.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperExif.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperExif.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.mapper;
+
+import java.lang.reflect.Array;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.enums.PropertyType;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.drew.imaging.PhotographicConversions;
+import com.drew.lang.Rational;
+import com.drew.metadata.Directory;
+import com.drew.metadata.Tag;
+import com.drew.metadata.exif.ExifDirectory;
+import com.drew.metadata.exif.GpsDirectory;
+import com.drew.metadata.jpeg.JpegDirectory;
+
+public class PropertyMapperExif extends AbstractPropertyMapper {
+
+    private static final Log LOG = LogFactory.getLog(PropertyMapperExif.class.getName());
+    private static String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss";
+
+    private Map<String, String> propMapExif = new HashMap<String, String> (); // tag to property id
+    private Map<String, String> propMapGps = new HashMap<String, String> ();  // tag to property id
+    private Map<String, String> propMapJpeg = new HashMap<String, String> (); // tag to property id
+    
+    protected Map<String, Object> propMap;
+
+    public boolean initialize(String cfgPrefix, String typeKey, Properties properties) {
+        super.initialize(cfgPrefix, typeKey, properties);
+        reset();
+        dateFormat = EXIF_DATE_FORMAT;
+        buildIdMap("exif", propMapExif, properties);
+        buildIdMap("gps", propMapGps, properties);
+        buildIdMap("jpeg", propMapJpeg, properties);
+        
+        return true;
+    }
+
+    public void reset() {
+        propMap = new HashMap<String, Object> ();
+    }
+    
+
+    public Map<String, Object> getMappedProperties() {
+        return propMap;
+    }
+    
+    private void buildIdMap(String dirKey, Map<String, String> propMap, Properties properties) {
+        Set<String> keys = properties.stringPropertyNames(); 
+        String prefix = propPrefix + "." + dirKey + ".id.";
+        for (String key : keys) {
+            if (key.startsWith(prefix)) {
+                String id = key.substring(prefix.length());
+                String cmisPropId = properties.getProperty(key).trim();
+                if (null == cmisPropId)
+                    throw new MapperException("Configuration key " + key + " must have a value assigned");
+                LOG.debug("Found mapping for type " + dirKey + " with " + id + " to " + cmisPropId);
+                propMap.put(id,  cmisPropId);
+            }
+        }
+    }
+
+    public String getMappedTypeId(String mimeType) {
+        return cmisTypeId;
+    }
+
+    public String getMappedPropertyId(String key) {
+        return null;
+    }
+
+    public Object convertValue(String id, PropertyDefinition<?> propDef, String strValue) {
+        return null;
+    }
+
+    private String getHexString(int tagType) {
+        StringBuffer hexStr = new StringBuffer();
+        hexStr.append(Integer.toHexString(tagType));
+        while (hexStr.length() < 4)
+            hexStr.insert(0, "0");
+        hexStr.insert(0, "0x");
+        return hexStr.toString();
+    }
+    /**
+     * store the property id mapped to this tag in a JPEG file in a local map
+     * @param dir
+     *      directory of tag
+     * @param tag
+     *      tag
+     */
+    
+    public void mapTagAndConvert(Directory dir, Tag tag, TypeDefinition td) {
+        String propId = null;
+        String hexStr = getHexString(tag.getTagType());
+        
+        if (GpsDirectory.class.equals(dir.getClass())) {
+            propId = propMapGps.get(hexStr);
+        } else if (ExifDirectory.class.equals(dir.getClass())) {
+            propId = propMapExif.get(hexStr);
+        } else if (JpegDirectory.class.equals(dir.getClass())) {
+            propId = propMapJpeg.get(hexStr);
+        } else
+            propId = null;
+        
+        if (null != propId) {
+            if (null != td) {
+                PropertyDefinition<?> pd = td.getPropertyDefinitions().get(propId);
+                if (null == pd)
+                    throw new MapperException("Unknown property id " + propId + " in type definition " + td.getId());
+                PropertyType pt = pd.getPropertyType();
+                Object convValue = convertValue(dir, tag, pt);
+                propMap.put(propId, convValue);
+            } else
+                propMap.put(propId, dir.getObject(tag.getTagType())); // omit conversion if no type definition is available
+        }
+    }
+    
+    public Object convertValue(Directory dir, Tag tag, PropertyType propType) {
+        
+        Object res = null;
+        String hexStr = getHexString(tag.getTagType());
+
+        // Handle all tags corresponding to their directory specifics
+        if (GpsDirectory.class.equals(dir.getClass())) {
+            // first check for those tags that need special consideration:
+            if ( GpsDirectory.TAG_GPS_LONGITUDE == tag.getTagType()) {
+                Object ref = dir.getObject(GpsDirectory.TAG_GPS_DEST_LONGITUDE_REF);
+                boolean mustInv = ref != null && ref.equals('W');
+                return convertGps(tag, dir, mustInv);
+            } else if ( GpsDirectory.TAG_GPS_LATITUDE == tag.getTagType()) {
+                Object ref = dir.getObject(GpsDirectory.TAG_GPS_DEST_LONGITUDE_REF);
+                boolean mustInv = ref != null && ref.equals('S');
+                return convertGps(tag, dir, mustInv);
+            } else {
+                String propId = propMapGps.get(hexStr);
+                LOG.debug("Found GPS tag '" + tag + "\', property mapped is: " + propId);
+                if (null == propId) {
+                    LOG.info("Ignoring EXIF tag '" + tag + "\' no property mapped to this tag.");
+                } else if (propType == null) {
+                    // should not happen and is a configuration error: we have a property id but no type
+                    LOG.error("Ignoring EXIF tag '" + tag + "\' no property type mapped to this tag.");
+                }
+                Object src = dir.getObject(tag.getTagType());        
+                Class<?> clazz = src.getClass();
+                if (clazz.equals(Rational.class)) {
+                    // expect a CMIS decimal property
+                    if (propType != PropertyType.DECIMAL)
+                        throw new MapperException("Tag value has type Rational and expected CMIS Decimal, but found: " + propType + " for tag: " + tag);
+                    double d = ((Rational) src).doubleValue();
+                    res = d;
+                } else if (clazz.equals(String.class)) {
+                    if (propType != PropertyType.STRING && propType != PropertyType.ID && propType != PropertyType.URI &&
+                            propType != PropertyType.HTML && propType != PropertyType.DATETIME)
+                        throw new MapperException("Tag value has type String and expected CMIS String, but found: " + propType + " for tag: " + tag);
+                    String s = ((String) src);
+                    res = s;
+                } else
+                res = null;
+            }
+        } else if (ExifDirectory.class.equals(dir.getClass())) {
+            // is there a property mapped to this tag?
+            String propId = propMapExif.get(hexStr);
+            LOG.debug("Found EXIF tag '" + tag + "\', property mapped is: " + propId);
+
+            if (null == propId) {
+                LOG.debug("Ignoring EXIF tag '" + tag + "\' no property mapped to this tag.");
+            } else if (propType == null) {
+                // should not happen and is a configuration error: we have a property id but no type
+                LOG.error("Ignoring EXIF tag '" + tag + "\' no property type mapped to this tag.");
+            } else {
+                Object src = dir.getObject(tag.getTagType());        
+                Class<?> clazz = src.getClass();
+                // handle arrays and map them to multi-value properties
+                if (clazz.isArray()) {
+                    LOG.error("Found a multi-value tag " + tag + ": multi value not implemented");
+                    return null;
+                }
+                if (clazz.equals(Rational.class)) {
+                    // expect a CMIS decimal property
+                    if (propType != PropertyType.DECIMAL)
+                        throw new MapperException("Tag value has type Rational and expected CMIS Decimal, but found: " + propType + " for tag: " + tag);
+                    
+                    if (tag.getTagType() == ExifDirectory.TAG_SHUTTER_SPEED) {
+                        // requires special handling, see Tika impl.
+                        double apexValue = ((Rational) src).doubleValue();
+                        res = PhotographicConversions.shutterSpeedToExposureTime(apexValue);
+                    } else if (tag.getTagType() == (ExifDirectory.TAG_APERTURE)) {
+                        double aperture =((Rational) src).doubleValue();
+                        double fStop = PhotographicConversions.apertureToFStop(aperture);
+                        res = fStop;
+                    } else {
+                        // convert to a double
+                        double d = ((Rational) src).doubleValue();
+                        res = d;
+                    }
+                } else if (clazz.equals(Integer.class)) {
+                    if (propType != PropertyType.INTEGER)
+                        throw new MapperException("Tag value has type Integer and expected CMIS Integer, but found: " + propType + " for tag: " + tag);
+                    // convert to a long
+                    long l = ((Integer) src).longValue();
+                    res = l;                                        
+                } else if (clazz.equals(String.class)) {
+                    if (propType != PropertyType.STRING && propType != PropertyType.ID && propType != PropertyType.URI &&
+                            propType != PropertyType.HTML && propType != PropertyType.DATETIME)
+                        throw new MapperException("Tag value has type String and expected CMIS String, but found: " + propType + " for tag: " + tag);
+                    // convert to a String
+                    if (propType == PropertyType.DATETIME) {
+                        // parse format: 2012:02:25 16:23:16
+                        DateFormat formatter = new SimpleDateFormat(dateFormat);
+                        GregorianCalendar cal;
+                        try {
+                            Date date = (Date)formatter.parse((String) src);
+                            // convert date to GreogorianCalendar as CMIS expects
+                            cal = new GregorianCalendar();
+                            cal.setTime(date);
+                        } catch (ParseException e) {
+                            LOG.error(e);
+                            throw new MapperException("Unrecognized date format in EXIF date tag: " + src + " for tag: " + tag + " expected: yyyy:MM:dd HH:mm:ss");
+                        }
+                        res = cal;                     
+                    } else {
+                        String s = ((String) src);
+                        res = s;
+                    }
+                } else if (clazz.equals(Date.class)) {
+                    if (propType != PropertyType.DATETIME)
+                        throw new MapperException("Tag value has type Date and expected CMIS DateTime, but found: " + propType + " for tag: " + tag);
+                    // convert to a String
+                    Date date = ((Date) src);
+                    // convert date to GreogorianCalendar as CMIS expects
+                    GregorianCalendar  cal= new GregorianCalendar();
+                    cal.setTime(date);
+                    res = cal;                                        
+                } else if (clazz.equals(Boolean.class)) {
+                    if (propType != PropertyType.BOOLEAN)
+                        throw new MapperException("Tag value has type Boolean and expected CMIS Boolean, but found: " + propType + " for tag: " + tag);
+                    // convert to a String
+                    Boolean b = ((Boolean) src);
+                    res = b;                                        
+                } else {
+                    LOG.debug("Tag value has unsupported type: " + clazz.getName() + " for EXIF tag: " + tag);
+                    // throw new MapperException("Tag value has unsupported type: " + clazz.getName() + " for tag: " + tag);
+                }                
+            }            
+        } else if (JpegDirectory.class.equals(dir.getClass())) {
+            // is there a property mapped to this tag?
+            String propId = propMapJpeg.get(hexStr);
+            LOG.debug("Found JPEG tag '" + tag + "\', property mapped is: " + propId);
+
+            if (null == propId) {
+                LOG.info("Ignoring JPEG tag '" + tag + "\' no property mapped to this tag.");
+            } else if (propType == null) {
+                // should not happen and is a configuration error: we have a property id but no type
+                LOG.error("Ignoring JPEG tag '" + tag + "\' no property type mapped to this tag.");
+            } else {
+                Object src = dir.getObject(tag.getTagType());        
+                Class<?> clazz = src.getClass();
+
+                if (clazz.equals(Integer.class)) {
+                    if (propType != PropertyType.INTEGER)
+                        throw new MapperException("Tag value has type Integer and expected CMIS Integer, but found: " + propType + " for tag: " + tag);
+                    // convert to a long
+                    long l = ((Integer) src).longValue();
+                    res = l;                                        
+                } else {
+                    LOG.debug("Tag value has unsupported type: " + clazz.getName() + " for JPEG tag: " + tag);
+                }
+            }            
+        }
+            
+        return res;        
+    }
+    
+    private static Object convertGps(Tag tag, Directory dir, boolean mustInvert) {
+        Double res = null; 
+        Object src = dir.getObject(tag.getTagType());
+        
+        Class<?> stringArrayClass = src.getClass();
+        Class<?> stringArrayComponentType = stringArrayClass.getComponentType();
+        if (!stringArrayClass.isArray() || null == stringArrayComponentType || Array.getLength(src) != 3) 
+            throw new MapperException("GPS coordinate \"" + tag + "\" has unknown type.");
+        if (!stringArrayComponentType.equals(Rational.class))
+            throw new MapperException("GPS coordinate \"" + tag + "\" has unknown component type (expected Rational, found: " + 
+                    stringArrayComponentType.getName() + ")");
+        // do conversion
+        Rational[] components;
+        components = (Rational[]) src;
+        int deg = components[0].intValue();
+        double min = components[1].doubleValue();
+        double sec = components[2].doubleValue();
+        Double d = (deg + min / 60 + sec / 3600);
+        if (d > 0.0 && mustInvert)
+            d = -d;
+        res = d;
+        return res;
+    }
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperTika.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperTika.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperTika.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/mapper/PropertyMapperTika.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.mapper;
+
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
+import org.apache.chemistry.opencmis.commons.enums.Cardinality;
+import org.apache.chemistry.opencmis.commons.enums.PropertyType;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class PropertyMapperTika extends AbstractPropertyMapper {
+
+    private static final Log LOG = LogFactory.getLog(PropertyMapperTika.class.getName());
+    
+    private Map<String, String> propMapTags = new HashMap<String, String> (); // tag to property id
+    private Map<String, String> tokenizerMap = new HashMap<String, String> (); // tag to tokenizer regexp
+
+    public PropertyMapperTika() {
+        reset();
+    }
+    
+    public boolean initialize(String cfgPrefix, String typeKey, Properties properties) {
+        super.initialize(cfgPrefix, typeKey, properties);
+        buildIdMap(typeKey, properties);
+        
+        return true;
+    }
+    
+    public void reset() {
+    }
+    
+    public String getMappedPropertyId(String key) {
+        String propId = propMapTags.get(key);
+        return propId;
+    }
+
+    public Object convertValue(String key, PropertyDefinition<?> propDef, final String strValue) {
+        Object value = null;
+        PropertyType pt = propDef.getPropertyType();
+        
+        if (null == pt)
+            value = null;
+        else {
+            switch (pt) {
+            case STRING:
+            case HTML:
+            case URI:
+            case ID:
+                if (propDef.getCardinality() == Cardinality.SINGLE)
+                    value = strValue;
+                else {
+                    String tokenizer = tokenizerMap.containsKey(key) ? tokenizerMap.get(key) : "\\W";
+                    String[] result = strValue.split(tokenizer);
+                    List<String> valList = new ArrayList<String>();
+                    for (String s : result)
+                        valList.add(s.trim());
+                    value = valList;
+                }
+                break;
+            case INTEGER:
+                if (propDef.getCardinality() == Cardinality.SINGLE)
+                    value = Integer.valueOf(strValue);
+                else {
+                        String tokenizer = tokenizerMap.containsKey(key) ? tokenizerMap.get(key) : "\\W";
+                        String[] result = strValue.split(tokenizer);
+                        List<Integer> valList = new ArrayList<Integer>();
+                        for (String s : result)
+                            valList.add(Integer.valueOf(s.trim()));
+                        value = valList;
+                    }
+                break;
+            case DECIMAL:
+                if (propDef.getCardinality() == Cardinality.SINGLE)
+                    value = Double.valueOf(strValue);                
+                else {
+                    String tokenizer = tokenizerMap.containsKey(key) ? tokenizerMap.get(key) : "[\\s;:]";                        
+                    String[] result = strValue.split(tokenizer);
+                        List<Double> valList = new ArrayList<Double>();
+                        for (String s : result)
+                            valList.add(Double.valueOf(s.trim()));
+                        value = valList;
+                    }
+                break;
+            case DATETIME:
+                try {
+                    SimpleDateFormat sdf = new SimpleDateFormat(dateFormat, new DateFormatSymbols(Locale.US));
+                    if (propDef.getCardinality() == Cardinality.SINGLE) {
+                        Date date = sdf.parse(strValue);
+                        GregorianCalendar cal = new GregorianCalendar();
+                        cal.setTime(date);
+                        value = date;
+                    } else {
+                        String tokenizer = tokenizerMap.containsKey(key) ? tokenizerMap.get(key) : "[;,:]";                        
+                        String[] result = strValue.split(tokenizer);
+                        List<GregorianCalendar> valList = new ArrayList<GregorianCalendar>();
+                        for (String s : result) {
+                            Date date = sdf.parse(s.trim());
+                            GregorianCalendar cal = new GregorianCalendar();
+                            cal.setTime(date);
+                            valList.add(cal);
+                        }
+                        value = valList;
+                    }
+                } catch (ParseException e) {
+                    LOG.error("Could not parse date: " + strValue + " (check date format");
+                    LOG.error(e);
+                    value = null;
+                    e.printStackTrace();
+                }
+                break;
+            default:
+                throw new MapperException("unknown property type " + pt);
+            }            
+        }
+        return value;
+    }
+    
+    void buildIdMap(String typeKey, Properties properties) {
+        Set<String> keys = properties.stringPropertyNames(); 
+        String prefix = propPrefix + ".id.";
+        String tokenizerPrefix = propPrefix + ".tokenizer.";
+
+        for (String key : keys) {
+            if (key.startsWith(prefix)) {
+                String id = key.substring(prefix.length());
+                String cmisPropId = properties.getProperty(key).trim();
+                if (null == cmisPropId)
+                    throw new MapperException("Configuration key " + key + " must have a value assigned");
+                LOG.debug("Found mapping for type " + typeKey + " with " + id + " to " + cmisPropId);
+                propMapTags.put(id,  cmisPropId);
+            }
+            if (key.startsWith(tokenizerPrefix)) {
+                String id = key.substring(tokenizerPrefix.length());
+                String regex = properties.getProperty(key).trim();
+                if (null == regex)
+                    throw new MapperException("Configuration key " + key + " must have a value assigned");
+                LOG.debug("Found tokenizer mapping for property " + id + " to " + regex);
+                tokenizerMap.put(id, regex);
+            }
+        }
+    }
+    
+    int getSize() {
+        return propMapTags.size();
+    }
+    
+ }

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/AbstractMetadataParser.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/AbstractMetadataParser.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/AbstractMetadataParser.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/AbstractMetadataParser.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.mapper.MapperException;
+import org.apache.chemistry.opencmis.client.mapper.PropertyMapper;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+
+public abstract class AbstractMetadataParser implements MetadataParser {
+    
+    // private static final Log LOG = LogFactory.getLog(AbstractMetadataParser.class.getName());
+
+    protected Map<String, Object> cmisProperties;
+    protected PropertyMapper mapper = null;
+    
+    protected AbstractMetadataParser() {
+    }
+
+    public void initialize(PropertyMapper mapper, String contentType) {
+        this.mapper = mapper;
+        reset();
+    }
+
+    public Map<String, Object> getCmisProperties() {
+        return cmisProperties;
+    }
+    
+    public void reset() {
+        String typeId = mapper.getMappedTypeId();
+        cmisProperties = new HashMap<String, Object>();
+        mapper.reset();
+
+        if (null == typeId)
+            throw new MapperException("No CMIS Type configured in this parser.");
+        cmisProperties.put(PropertyIds.OBJECT_TYPE_ID, typeId);
+    }
+    
+    public String[] getContentTypes() {
+        return mapper.getContentTypes();
+    }
+    
+    public String getMappedTypeId() {
+        return mapper.getMappedTypeId();
+    }
+    
+    public PropertyMapper getMapper() {
+        return mapper;
+    }
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParser.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParser.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParser.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParser.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.parser;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.mapper.MapperException;
+import org.apache.chemistry.opencmis.client.mapper.PropertyMapper;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+
+/**
+ * This interface is used to extract metadata from content. An instance is 
+ * responsible to parse the content and extract the metadata. The metadata
+ * must be stored in a CMIS property bag. Implementations of this class are
+ * created by the Configurator depending on the Content-Type to parse and
+ * the corresponding parser configuration
+ * 
+ * @author Jens
+ *
+ */
+public interface MetadataParser {
+    
+    /**
+     * Initialize a parser with a given property mapper and a content type
+     * @param mapper
+     *      PropertyMapper used to map tags to properties and convert values
+     * @param contentType
+     *      content type of file to extract
+     */
+    void initialize(PropertyMapper mapper, String contentType);
+    
+    /**
+     * get ready for parsing a new file
+     */
+    void reset();
+    
+    /**
+     * Parse a file and extract all metadata and store them in a CMIS property bag
+     * @param f
+     *      file to parse
+     * @throws MapperException
+     */
+    void extractMetadata(File f, TypeDefinition td) throws MapperException;
+    
+    /**
+     * Return all found metadata, called after parsing is completed.
+     * @return
+     *      extracted CMIS properties
+     */
+    Map<String, Object> getCmisProperties();
+    
+    /**
+     * get all content types handled by this parser
+     * @return
+     *      array with content types
+     */
+    String[] getContentTypes();
+    
+    /**
+     * get the CMIS type id used by this type
+     * @return
+     *      CMIS type id
+     */
+    String getMappedTypeId();
+    
+    /**
+     * get the associated property mapper for this CMIS type
+     * 
+     * @return
+     *      property mapper
+     */
+    PropertyMapper getMapper();
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserExif.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserExif.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserExif.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserExif.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.parser;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.client.mapper.MapperException;
+import org.apache.chemistry.opencmis.client.mapper.PropertyMapperExif;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.drew.imaging.ImageMetadataReader;
+import com.drew.imaging.ImageProcessingException;
+import com.drew.metadata.Directory;
+import com.drew.metadata.Tag;
+
+/**
+ * A parser implementation using a lower level interface to get more control about the 
+ * EXIF tags than Tika provides
+ * 
+ * @author Jens
+ *
+ */
+public class MetadataParserExif extends AbstractMetadataParser  {
+
+    private static final Log LOG = LogFactory.getLog(MetadataParserExif.class.getName());
+    
+    public void extractMetadata(File f, TypeDefinition td) throws MapperException {
+        
+        reset();
+        
+        // see  http://code.google.com/p/metadata-extractor/wiki/GettingStarted
+        try {
+            com.drew.metadata.Metadata metadata = ImageMetadataReader.readMetadata(f);
+            Iterator<?> it = metadata.getDirectoryIterator();
+            while (it.hasNext()) {
+                Directory directory = (com.drew.metadata.Directory) it.next();
+                Iterator<?> tagIt = directory.getTagIterator();
+                while (tagIt.hasNext()) {
+                    Tag tag = (Tag) tagIt.next();
+                    Object o = directory.getObject(tag.getTagType());
+                    LOG.debug("Tag: " + tag + ", value: " + o + ", class: " + o.getClass() + 
+                            ", tag type: " + tag.getTagType() + ", hex-value: " + tag.getTagTypeHex());
+                    if (null != cmisProperties) {
+                        ((PropertyMapperExif)mapper).mapTagAndConvert(directory, tag, td);
+                    }
+                }
+            }
+            Map<String, Object> props = ((PropertyMapperExif)mapper).getMappedProperties();
+            cmisProperties.putAll(props);
+        } catch (ImageProcessingException e) {            
+            LOG.error(e);
+        }
+
+    }
+
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserTika.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserTika.java?rev=1305762&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserTika.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-client/src/main/java/org/apache/chemistry/opencmis/client/parser/MetadataParserTika.java Tue Mar 27 07:43:31 2012
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import org.apache.chemistry.opencmis.client.mapper.MapperException;
+import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.enums.PropertyType;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.AutoDetectParser;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.parser.Parser;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A metadata parser using the Apache Tika library
+ * @author Jens
+ *
+ */
+public class MetadataParserTika extends AbstractMetadataParser {
+
+    private static final Log LOG = LogFactory.getLog(MetadataParserTika.class.getName());
+
+    public MetadataParserTika() {        
+    }
+    
+    public void extractMetadata(File f, TypeDefinition td) throws MapperException {
+        try {
+            InputStream stream = new FileInputStream(f);
+            Metadata metadata = new Metadata();
+            ContentHandler handler = new DefaultHandler();
+            Parser parser = new AutoDetectParser(); 
+            ParseContext context = new ParseContext();
+            parser.parse(stream, handler, metadata, context);
+
+            reset();
+            
+            for (String key : metadata.names()) {
+                String val = metadata.get(key);
+                LOG.debug("Found metadata \'" + key + "\': " + val);      
+                if (null != cmisProperties) {
+                    String propertyId = mapper.getMappedPropertyId(key);
+                    if (null != propertyId && null != val) {
+                        if (td != null) {
+                            PropertyDefinition<?> propDef = td.getPropertyDefinitions().get(propertyId);
+                            if (null == propDef)
+                                throw new MapperException("Mapping error: unknown property "+ propertyId + " in type definition " + td.getId());
+                            PropertyType propertyType = propDef.getPropertyType();
+                            Object convVal = mapper.convertValue(propertyId, propDef, val);
+                            if (null != convVal)
+                                cmisProperties.put(propertyId, convVal);
+                        } else
+                            cmisProperties.put(propertyId, val); // omit conversion if no type definition is available
+                    }
+                }
+            }
+
+        } catch (Exception e) {
+            LOG.error(e);
+            throw new MapperException("Extracting metadata failed for file " + f.getAbsolutePath(), e);
+        }
+    }    
+    
+    public void listMetadata(File f) throws MapperException {
+        try {
+            InputStream stream = new FileInputStream(f);
+            Metadata metadata = new Metadata();
+            ContentHandler handler = new DefaultHandler();
+            Parser parser = new AutoDetectParser(); 
+            ParseContext context = new ParseContext();
+            parser.parse(stream, handler, metadata, context);
+
+            for (String key : metadata.names()) {
+                String val = metadata.get(key);
+                LOG.info("Found metadata \'" + key + "\': " + val);      
+            }
+
+        } catch (Exception e) {
+            LOG.error(e);
+            throw new MapperException("Extracting metadata failed, file not found: " + f.getAbsolutePath(), e);
+        }
+    } 
+}



Mime
View raw message