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