001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.camel.processor; 019 020import static java.util.Collections.singletonList; 021import static java.util.Optional.empty; 022import static java.util.Optional.of; 023import static java.util.stream.Collectors.toList; 024import static org.fcrepo.camel.FcrepoHeaders.FCREPO_AGENT; 025import static org.fcrepo.camel.FcrepoHeaders.FCREPO_DATE_TIME; 026import static org.fcrepo.camel.FcrepoHeaders.FCREPO_EVENT_ID; 027import static org.fcrepo.camel.FcrepoHeaders.FCREPO_EVENT_TYPE; 028import static org.fcrepo.camel.FcrepoHeaders.FCREPO_RESOURCE_TYPE; 029import static org.fcrepo.camel.FcrepoHeaders.FCREPO_URI; 030 031import java.io.InputStream; 032import java.io.IOException; 033import java.util.ArrayList; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.List; 037import java.util.Map; 038import java.util.Optional; 039import java.util.Set; 040 041import com.fasterxml.jackson.databind.JsonNode; 042import com.fasterxml.jackson.databind.ObjectMapper; 043 044import org.apache.camel.Exchange; 045import org.apache.camel.Processor; 046 047/** 048 * Converts a Fedora Message into camel-based headers. 049 * 050 * @author acoburn 051 */ 052public class EventProcessor implements Processor { 053 054 private static final ObjectMapper mapper = new ObjectMapper(); 055 056 /** 057 * Process the Fedora message 058 * 059 * @param exchange the current camel message exchange 060 */ 061 public void process(final Exchange exchange) throws IOException { 062 final Object body = exchange.getIn().getBody(); 063 final Map<String, List<String>> data = new HashMap<>(); 064 if (body != null) { 065 // In the event that the message was already converted to a Map 066 if (body instanceof Map) { 067 data.putAll(getValuesFromMap((Map)body)); 068 } else if (body instanceof String) { 069 data.putAll(getValuesFromJson(mapper.readTree((String)body))); 070 } else if (body instanceof InputStream) { 071 data.putAll(getValuesFromJson(mapper.readTree((InputStream)body))); 072 } 073 } 074 075 final Set<String> singleValuedFields = new HashSet<String>(); 076 singleValuedFields.add(FCREPO_URI); 077 singleValuedFields.add(FCREPO_DATE_TIME); 078 singleValuedFields.add(FCREPO_EVENT_ID); 079 080 data.entrySet().stream().filter(entry -> entry.getValue() != null) 081 .filter(entry -> !entry.getValue().isEmpty()).forEach(entry -> { 082 if (singleValuedFields.contains(entry.getKey())) { 083 exchange.getIn().setHeader(entry.getKey(), entry.getValue().get(0)); 084 } else { 085 exchange.getIn().setHeader(entry.getKey(), entry.getValue()); 086 } 087 }); 088 } 089 090 private Map<String, List<String>> getValuesFromJson(final JsonNode body) { 091 final Map<String, List<String>> data = new HashMap<>(); 092 getValues(body, "@id").ifPresent(id -> data.put(FCREPO_URI, id)); 093 getValues(body, "id").ifPresent(id -> data.putIfAbsent(FCREPO_URI, id)); 094 095 getValues(body, "@type").ifPresent(type -> data.put(FCREPO_RESOURCE_TYPE, type)); 096 getValues(body, "type").ifPresent(type -> data.putIfAbsent(FCREPO_RESOURCE_TYPE, type)); 097 098 if (body.has("wasGeneratedBy")) { 099 final JsonNode generatedBy = body.get("wasGeneratedBy"); 100 getValues(generatedBy, "type").ifPresent(type -> data.put(FCREPO_EVENT_TYPE, type)); 101 getValues(generatedBy, "atTime").ifPresent(time -> data.put(FCREPO_DATE_TIME, time)); 102 getValues(generatedBy, "identifier").ifPresent(id -> data.put(FCREPO_EVENT_ID, id)); 103 } 104 105 if (body.has("wasAttributedTo")) { 106 final JsonNode attributedTo = body.get("wasAttributedTo"); 107 if (attributedTo.isArray()) { 108 final List<String> agents = new ArrayList<>(); 109 for (final JsonNode agent : attributedTo) { 110 getString(agent, "name").ifPresent(agents::add); 111 } 112 data.put(FCREPO_AGENT, agents); 113 } else { 114 getString(attributedTo, "name").ifPresent(name -> data.put(FCREPO_AGENT, singletonList(name))); 115 } 116 } 117 118 return data; 119 } 120 121 private static Optional<String> getString(final JsonNode node, final String fieldName) { 122 if (node.has(fieldName)) { 123 final JsonNode field = node.get(fieldName); 124 if (field.isTextual()) { 125 return of(field.asText()); 126 } 127 } 128 return empty(); 129 } 130 131 private static Optional<List<String>> getValues(final JsonNode node, final String fieldName) { 132 if (node.has(fieldName)) { 133 final JsonNode field = node.get(fieldName); 134 if (field.isArray()) { 135 final List<String> elements = new ArrayList<>(); 136 field.elements().forEachRemaining(elem -> { 137 if (elem.isTextual()) { 138 elements.add(elem.asText()); 139 } 140 }); 141 return of(elements); 142 } else if (field.isTextual()) { 143 return of(singletonList(field.asText())); 144 } 145 } 146 return empty(); 147 } 148 149 @SuppressWarnings("unchecked") 150 private static Map<String, List<String>> getValuesFromMap(final Map body) { 151 final Map<String, Object> values = (Map<String, Object>)body; 152 final Map<String, List<String>> data = new HashMap<>(); 153 if (values.containsKey("@id")) { 154 data.put(FCREPO_URI, singletonList((String)values.get("@id"))); 155 } 156 if (values.containsKey("id")) { 157 data.putIfAbsent(FCREPO_URI, singletonList((String)values.get("id"))); 158 } 159 160 if (values.containsKey("@type")) { 161 data.put(FCREPO_RESOURCE_TYPE, (List<String>)values.get("@type")); 162 } 163 if (values.containsKey("type")) { 164 data.putIfAbsent(FCREPO_RESOURCE_TYPE, (List<String>)values.get("type")); 165 } 166 167 final Map<String, Object> wasGeneratedBy = (Map<String, Object>)values.get("wasGeneratedBy"); 168 169 if (wasGeneratedBy != null) { 170 if (wasGeneratedBy.containsKey("type")) { 171 data.put(FCREPO_EVENT_TYPE, (List<String>)wasGeneratedBy.get("type")); 172 } 173 data.put(FCREPO_EVENT_ID, singletonList((String)wasGeneratedBy.get("identifier"))); 174 data.put(FCREPO_DATE_TIME, singletonList((String)wasGeneratedBy.get("atTime"))); 175 } 176 177 final List<Map<String, String>> wasAttributedTo = (List<Map<String, String>>)values.get("wasAttributedTo"); 178 if (wasAttributedTo != null) { 179 data.put(FCREPO_AGENT, 180 wasAttributedTo.stream().map(agent -> agent.get("name")).collect(toList())); 181 } 182 183 return data; 184 } 185}