/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.camel.component.catalog.content;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.camel.Message;
import org.apache.camel.component.file.GenericFile;
import org.apache.camel.component.file.GenericFileMessage;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.Files;
import ddf.catalog.Constants;
import ddf.catalog.content.data.impl.ContentItemImpl;
import ddf.catalog.content.operation.CreateStorageRequest;
import ddf.catalog.content.operation.StorageRequest;
import ddf.catalog.content.operation.UpdateStorageRequest;
import ddf.catalog.content.operation.impl.CreateStorageRequestImpl;
import ddf.catalog.content.operation.impl.UpdateStorageRequestImpl;
import ddf.catalog.data.Metacard;
import ddf.catalog.operation.CreateResponse;
import ddf.catalog.operation.DeleteRequest;
import ddf.catalog.operation.DeleteResponse;
import ddf.catalog.operation.Update;
import ddf.catalog.operation.UpdateResponse;
import ddf.catalog.operation.impl.DeleteRequestImpl;
import ddf.catalog.source.IngestException;
import ddf.catalog.source.SourceUnavailableException;
import ddf.mime.MimeTypeMapper;
import ddf.mime.MimeTypeResolutionException;
public class ContentProducerDataAccessObject {
private static final transient Logger LOGGER = LoggerFactory.getLogger(
ContentProducerDataAccessObject.class);
public File getFileUsingRefKey(boolean storeRefKey, Message in)
throws ContentComponentException {
File ingestedFile;
try {
if (!storeRefKey) {
ingestedFile = ((GenericFile<File>) in.getBody()).getFile();
} else {
WatchEvent<Path> pathWatchEvent =
(WatchEvent<Path>) ((GenericFileMessage) in).getGenericFile()
.getFile();
ingestedFile = pathWatchEvent.context()
.toFile();
}
} catch (ClassCastException e) {
throw new ContentComponentException(
"Unable to cast message body to Camel GenericFile, so unable to process ingested file");
}
return ingestedFile;
}
public WatchEvent.Kind<Path> getEventType(boolean storeRefKey, Message in) {
if (storeRefKey) {
WatchEvent<Path> pathWatchEvent =
(WatchEvent<Path>) ((GenericFileMessage) in).getGenericFile()
.getFile();
return pathWatchEvent.kind();
} else {
return StandardWatchEventKinds.ENTRY_CREATE;
}
}
public String getMimeType(ContentEndpoint endpoint, File ingestedFile)
throws ContentComponentException {
String fileExtension = FilenameUtils.getExtension(ingestedFile.getAbsolutePath());
String mimeType = null;
MimeTypeMapper mimeTypeMapper = endpoint.getComponent()
.getMimeTypeMapper();
if (mimeTypeMapper != null && ingestedFile.exists()) {
try (InputStream inputStream = Files.asByteSource(ingestedFile)
.openStream()) {
if (fileExtension.equalsIgnoreCase("xml")) {
mimeType = mimeTypeMapper.guessMimeType(inputStream, fileExtension);
} else {
mimeType = mimeTypeMapper.getMimeTypeForFileExtension(fileExtension);
}
} catch (MimeTypeResolutionException | IOException e) {
throw new ContentComponentException(e);
}
} else if (ingestedFile.exists()) {
LOGGER.debug("Did not find a MimeTypeMapper service");
throw new ContentComponentException(
"Unable to find a mime type for the ingested file " + ingestedFile.getName());
}
return mimeType;
}
public void createContentItem(FileSystemPersistenceProvider fileIdMap, ContentEndpoint endpoint,
File ingestedFile, WatchEvent.Kind<Path> eventType, String mimeType,
Map<String, Object> headers) throws SourceUnavailableException, IngestException {
LOGGER.debug("Creating content item.");
String key = String.valueOf(ingestedFile.getAbsolutePath()
.hashCode());
String id = fileIdMap.loadAllKeys()
.contains(key) ? String.valueOf(fileIdMap.loadFromPersistence(key)) : null;
if (StandardWatchEventKinds.ENTRY_CREATE.equals(eventType)) {
CreateStorageRequest createRequest =
new CreateStorageRequestImpl(Collections.singletonList(new ContentItemImpl(Files.asByteSource(
ingestedFile), mimeType, ingestedFile.getName(), null)), null);
processHeaders(headers, createRequest, ingestedFile);
CreateResponse createResponse = endpoint.getComponent()
.getCatalogFramework()
.create(createRequest);
if (createResponse != null) {
List<Metacard> createdMetacards = createResponse.getCreatedMetacards();
for (Metacard metacard : createdMetacards) {
fileIdMap.store(key, metacard.getId());
LOGGER.debug("content item created with id = {}", metacard.getId());
}
}
} else if (StandardWatchEventKinds.ENTRY_MODIFY.equals(eventType)) {
UpdateStorageRequest updateRequest =
new UpdateStorageRequestImpl(Collections.singletonList(new ContentItemImpl(id,
Files.asByteSource(ingestedFile),
mimeType,
ingestedFile.getName(),
0,
null)), null);
processHeaders(headers, updateRequest, ingestedFile);
UpdateResponse updateResponse = endpoint.getComponent()
.getCatalogFramework()
.update(updateRequest);
if (updateResponse != null) {
List<Update> updatedMetacards = updateResponse.getUpdatedMetacards();
for (Update update : updatedMetacards) {
LOGGER.debug("content item updated with id = {}",
update.getNewMetacard()
.getId());
}
}
} else if (StandardWatchEventKinds.ENTRY_DELETE.equals(eventType)) {
DeleteRequest deleteRequest = new DeleteRequestImpl(id);
DeleteResponse deleteResponse = endpoint.getComponent()
.getCatalogFramework()
.delete(deleteRequest);
if (deleteResponse != null) {
List<Metacard> deletedMetacards = deleteResponse.getDeletedMetacards();
for (Metacard delete : deletedMetacards) {
fileIdMap.delete(ingestedFile.getAbsolutePath());
LOGGER.debug("content item deleted with id = {}", delete.getId());
}
}
}
}
public void processHeaders(Map<String, Object> headers, StorageRequest storageRequest,
File ingestedFile) {
Map<String, Serializable> attributeOverrideHeaders = new HashMap<>((Map) headers.get(
Constants.ATTRIBUTE_OVERRIDES_KEY));
if (!attributeOverrideHeaders.isEmpty()) {
storageRequest.getProperties()
.put(Constants.ATTRIBUTE_OVERRIDES_KEY,
(Serializable) attributeOverrideHeaders);
}
if (headers.containsKey(Constants.STORE_REFERENCE_KEY)) {
storageRequest.getProperties()
.put(Constants.STORE_REFERENCE_KEY, ingestedFile.getAbsolutePath());
}
}
}