001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006 007package org.fcrepo.kernel.impl.observer; 008 009import org.fcrepo.kernel.api.identifiers.FedoraId; 010import org.fcrepo.kernel.api.observer.Event; 011import org.fcrepo.kernel.api.observer.EventType; 012import org.fcrepo.kernel.api.operations.ResourceOperation; 013import org.fcrepo.kernel.impl.util.UserUtil; 014 015import java.net.URI; 016import java.time.Instant; 017import java.util.HashSet; 018import java.util.Objects; 019import java.util.Set; 020 021/** 022 * Converts a ResourceOperation into an Event. 023 * 024 * @author pwinckles 025 */ 026public class ResourceOperationEventBuilder implements EventBuilder { 027 028 private FedoraId fedoraId; 029 private Set<EventType> types; 030 private Set<String> resourceTypes; 031 private String userID; 032 private String userAgent; 033 private String baseUrl; 034 private Instant date; 035 private String userAgentBaseUri; 036 037 /** 038 * Creates a new EventBuilder based on an ResourceOperation 039 * 040 * @param fedoraId the FedoraId the operation is on 041 * @param operation the ResourceOperation to create an event for 042 * @param userAgentBaseUri the base uri of the user agent, optional 043 * @return new builder 044 */ 045 public static ResourceOperationEventBuilder fromResourceOperation(final FedoraId fedoraId, 046 final ResourceOperation operation, 047 final String userAgentBaseUri) { 048 final var builder = new ResourceOperationEventBuilder(); 049 builder.fedoraId = fedoraId; 050 builder.date = Instant.now(); 051 builder.resourceTypes = new HashSet<>(); 052 builder.userID = operation.getUserPrincipal(); 053 builder.types = new HashSet<>(); 054 builder.types.add(mapOperationToEventType(operation)); 055 builder.userAgentBaseUri = userAgentBaseUri; 056 return builder; 057 } 058 059 private static EventType mapOperationToEventType(final ResourceOperation operation) { 060 switch (operation.getType()) { 061 case CREATE: 062 case OVERWRITE_TOMBSTONE: 063 return EventType.RESOURCE_CREATION; 064 case UPDATE: 065 case UPDATE_HEADERS: 066 return EventType.RESOURCE_MODIFICATION; 067 case DELETE: 068 return EventType.RESOURCE_DELETION; 069 case PURGE: 070 return EventType.RESOURCE_PURGE; 071 case FOLLOW: 072 return EventType.INBOUND_REFERENCE; 073 default: 074 throw new IllegalStateException( 075 String.format("There is no EventType mapping for ResourceOperation type %s on operation %s", 076 operation.getType(), operation)); 077 } 078 } 079 080 private ResourceOperationEventBuilder() { 081 // Intentionally left blank 082 } 083 084 @Override 085 public EventBuilder merge(final EventBuilder other) { 086 if (other == null) { 087 return this; 088 } 089 090 if (!(other instanceof ResourceOperationEventBuilder)) { 091 throw new IllegalStateException( 092 String.format("Cannot merge EventBuilders because they are different types <%s> and <%s>", 093 this.getClass(), other.getClass())); 094 } 095 096 final var otherCast = (ResourceOperationEventBuilder) other; 097 098 if (!this.fedoraId.equals(otherCast.fedoraId)) { 099 throw new IllegalStateException( 100 String.format("Cannot merge events because they are for different resources: <%s> and <%s>", 101 this, otherCast)); 102 } 103 104 this.types.addAll(otherCast.types); 105 this.resourceTypes.addAll(otherCast.resourceTypes); 106 107 if (this.date.isBefore(otherCast.date)) { 108 this.date = otherCast.date; 109 } 110 111 return this; 112 } 113 114 @Override 115 public EventBuilder withResourceTypes(final Set<String> resourceTypes) { 116 this.resourceTypes = Objects.requireNonNullElse(resourceTypes, new HashSet<>()); 117 return this; 118 } 119 120 @Override 121 public EventBuilder withBaseUrl(final String baseUrl) { 122 this.baseUrl = baseUrl; 123 return this; 124 } 125 126 @Override 127 public EventBuilder withUserAgent(final String userAgent) { 128 this.userAgent = userAgent; 129 return this; 130 } 131 132 @Override 133 public Event build() { 134 URI userUri = null; 135 if (userID != null) { 136 userUri = UserUtil.getUserURI(userID, userAgentBaseUri); 137 } 138 return new EventImpl(fedoraId, types, resourceTypes, userID, userUri, userAgent, baseUrl, date); 139 } 140 141 @Override 142 public String toString() { 143 return "ResourceOperationEventBuilder{" + 144 "fedoraId=" + fedoraId + 145 ", types=" + types + 146 ", resourceTypes=" + resourceTypes + 147 ", userID='" + userID + '\'' + 148 ", userAgent='" + userAgent + '\'' + 149 ", baseUrl='" + baseUrl + '\'' + 150 ", date=" + date + 151 '}'; 152 } 153 154}