ref #9607 replacing class local factory methods and heplers in CdmImageInfo by servic...
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / MediaServiceImpl.java
index a00bb7d60ead6e1a62b4f2cfbd485834b258c09e..a19c42155e751581d072f9962b3836bf258d2fe8 100644 (file)
@@ -9,11 +9,17 @@
 \r
 package eu.etaxonomy.cdm.api.service;\r
 \r
+import java.io.IOException;\r
 import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.HashMap;\r
 import java.util.List;\r
+import java.util.Map;\r
 import java.util.Set;\r
 import java.util.UUID;\r
+import java.util.stream.Collectors;\r
 \r
+import org.apache.http.HttpException;\r
 import org.springframework.beans.factory.annotation.Autowired;\r
 import org.springframework.stereotype.Service;\r
 import org.springframework.transaction.annotation.Transactional;\r
@@ -21,8 +27,10 @@ import org.springframework.transaction.annotation.Transactional;
 import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;\r
 import eu.etaxonomy.cdm.api.service.config.MediaDeletionConfigurator;\r
 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;\r
+import eu.etaxonomy.cdm.api.service.media.MediaInfoFactory;\r
 import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
+import eu.etaxonomy.cdm.common.media.CdmImageInfo;\r
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;\r
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
@@ -37,7 +45,11 @@ import eu.etaxonomy.cdm.model.description.TextData;
 import eu.etaxonomy.cdm.model.location.NamedArea;\r
 import eu.etaxonomy.cdm.model.media.Media;\r
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
+import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;\r
 import eu.etaxonomy.cdm.model.media.Rights;\r
+import eu.etaxonomy.cdm.model.metadata.CdmPreference;\r
+import eu.etaxonomy.cdm.model.metadata.PreferencePredicate;\r
+import eu.etaxonomy.cdm.model.metadata.PreferenceSubject;\r
 import eu.etaxonomy.cdm.model.name.TaxonName;\r
 import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;\r
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
@@ -61,6 +73,10 @@ public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> i
     private ITaxonService taxonService;\r
        @Autowired\r
     private INameService nameService;\r
+       @Autowired\r
+       private IPreferenceService prefsService;\r
+    @Autowired\r
+    private MediaInfoFactory mediaInfoFactory; // FIXME define and use interface\r
 \r
 \r
        @Override\r
@@ -96,6 +112,17 @@ public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> i
                return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);\r
        }\r
 \r
+        @Override\r
+        @Transactional(readOnly=false)\r
+        public DeleteResult delete(Set<UUID> mediaUuids, MediaDeletionConfigurator config) {\r
+            DeleteResult result = new DeleteResult();\r
+            for (UUID uuid:mediaUuids){\r
+                result.includeResult(delete(uuid, config));\r
+            }\r
+            return result;\r
+\r
+        }\r
+\r
     @Override\r
     @Transactional(readOnly=false)\r
     public DeleteResult delete(UUID mediaUuid, MediaDeletionConfigurator config) {\r
@@ -182,13 +209,7 @@ public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> i
         while(textData.getMedia().contains(media)){\r
             textData.removeMedia(media);\r
         }\r
-        //if the textData contains text it should not be deleted\r
-        if (textData.getMedia().isEmpty() && textData.getMultilanguageText().isEmpty()){\r
-            desc.removeElement(textData);\r
-        }\r
-        if (desc.getElements().isEmpty()){\r
-            describable.removeDescription(desc);\r
-        }\r
+\r
         return describable;\r
     }\r
 \r
@@ -208,10 +229,9 @@ public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> i
             String message = null;\r
             if (ref instanceof MediaRepresentation){\r
                 continue;\r
-            }\r
-            if (ref instanceof TextData){\r
+            }else if (ref instanceof TextData){\r
                 TextData textData = HibernateProxyHelper.deproxy(ref, TextData.class);\r
-                DescriptionBase description = HibernateProxyHelper.deproxy(textData.getInDescription(), DescriptionBase.class);\r
+                DescriptionBase<?> description = HibernateProxyHelper.deproxy(textData.getInDescription(), DescriptionBase.class);\r
 \r
                 if (description instanceof TaxonDescription){\r
                     TaxonDescription desc = HibernateProxyHelper.deproxy(description, TaxonDescription.class);\r
@@ -239,8 +259,7 @@ public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> i
                         result.setAbort();\r
                     }\r
                 }\r
-\r
-            }if (ref instanceof MediaSpecimen){\r
+            }else if (ref instanceof MediaSpecimen){\r
                message = "The media can't be deleted from the database because it is referenced by a mediaspecimen. ("+((MediaSpecimen)ref).getTitleCache()+")";\r
                result.setAbort();\r
             }else {\r
@@ -250,11 +269,84 @@ public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> i
             if (message != null){\r
                 result.addException(new ReferencedObjectUndeletableException(message));\r
                 result.addRelatedObject(ref);\r
+            }\r
+        }\r
+\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * Reads the metadata as stored in the file or web resource and filters the data by the include and exclude lists of key names\r
+     * as stored in the data base properties {@link PreferencePredicate#MediaMetadataKeynameExcludes} and {@link PreferencePredicate#MediaMetadataKeynameExcludes}\r
+     * <p>\r
+     * Metadata of multiple parts is merged into one common metadata map whereas the later part being read may overwrite data from previous parts.\r
+     * The consequences of this can be neglected since we don't expect that multiple parts are actually being used.\r
+     *\r
+     * @param representation\r
+     * @return\r
+     * @throws IOException\r
+     * @throws HttpException\r
+     */\r
+    @Override\r
+    public Map<String, String> readResourceMetadataFiltered(MediaRepresentation representation) throws IOException, HttpException {\r
 \r
+        List<String> includes = mediaMetadataKeyIncludes();\r
+        List<String> excludes = mediaMetadataKeyExludes();\r
+        Map<String, String> metadata = new HashMap<>();\r
+\r
+        for(MediaRepresentationPart part : representation.getParts()) {\r
+            CdmImageInfo iInfo =  mediaInfoFactory.cdmImageInfoWithMetaData(part.getUri());\r
+            if(iInfo.getMetaData() != null) {\r
+                metadata.putAll(iInfo.getMetaData());\r
             }\r
+        }\r
 \r
+        if(logger.isDebugEnabled()) {\r
+            logger.debug("meta data as read from all parts: " + metadata.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(", ", "{", "}")));\r
         }\r
 \r
-        return result;\r
+        if(!includes.isEmpty()) {\r
+            metadata = metadata.entrySet()\r
+                    .stream()\r
+                    .filter( e -> containsCaseInsensitive(e.getKey(), includes))\r
+                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\r
+            if(logger.isDebugEnabled()) {\r
+                logger.debug("meta filtered by includes: " + metadata.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(", ", "{", "}")));\r
+            }\r
+        }\r
+        if(!excludes.isEmpty()) {\r
+            metadata = metadata.entrySet()\r
+                    .stream()\r
+                    .filter( e -> !containsCaseInsensitive(e.getKey(), excludes))\r
+                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\r
+            if(logger.isDebugEnabled()) {\r
+                logger.debug("meta filtered by excludes: " + metadata.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(", ", "{", "}")));\r
+            }\r
+        }\r
+\r
+        if(metadata == null) {\r
+            metadata = new HashMap<>();\r
+        }\r
+        return metadata;\r
+    }\r
+\r
+    private boolean containsCaseInsensitive(String s, List<String> l){\r
+        return l.stream().anyMatch(x -> x.equalsIgnoreCase(s));\r
+    }\r
+\r
+    protected List<String> mediaMetadataKeyExludes(){\r
+        CdmPreference pref = prefsService.findExact(CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaMetadataKeynameExcludes));\r
+        if(pref == null) {\r
+            return new ArrayList<>();\r
+        }\r
+        return pref.splitStringListValue();\r
+    }\r
+\r
+    protected List<String> mediaMetadataKeyIncludes(){\r
+        CdmPreference pref = prefsService.findExact(CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaMetadataKeynameIncludes));\r
+        if(pref == null) {\r
+            return Arrays.asList(PreferencePredicate.MediaMetadataKeynameIncludes.getDefaultValue().toString().split(","));\r
+        }\r
+        return pref.splitStringListValue();\r
     }\r
 }\r