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 private String userAgentBaseUri; 048 049 /** 050 * Creates a new EventBuilder based on an ResourceOperation 051 * 052 * @param fedoraId the FedoraId the operation is on 053 * @param operation the ResourceOperation to create an event for 054 * @param userAgentBaseUri the base uri of the user agent, optional 055 * @return new builder 056 */ 057 public static ResourceOperationEventBuilder fromResourceOperation(final FedoraId fedoraId, 058 final ResourceOperation operation, 059 final String userAgentBaseUri) { 060 final var builder = new ResourceOperationEventBuilder(); 061 builder.fedoraId = fedoraId; 062 builder.date = Instant.now(); 063 builder.resourceTypes = new HashSet<>(); 064 builder.userID = operation.getUserPrincipal(); 065 builder.types = new HashSet<>(); 066 builder.types.add(mapOperationToEventType(operation)); 067 builder.userAgentBaseUri = userAgentBaseUri; 068 return builder; 069 } 070 071 private static EventType mapOperationToEventType(final ResourceOperation operation) { 072 switch (operation.getType()) { 073 case CREATE: 074 return EventType.RESOURCE_CREATION; 075 case UPDATE: 076 return EventType.RESOURCE_MODIFICATION; 077 case DELETE: 078 return EventType.RESOURCE_DELETION; 079 case PURGE: 080 return EventType.RESOURCE_PURGE; 081 case FOLLOW: 082 return EventType.INBOUND_REFERENCE; 083 default: 084 throw new IllegalStateException( 085 String.format("There is no EventType mapping for ResourceOperation type %s on operation %s", 086 operation.getType(), operation)); 087 } 088 } 089 090 private ResourceOperationEventBuilder() { 091 // Intentionally left blank 092 } 093 094 @Override 095 public EventBuilder merge(final EventBuilder other) { 096 if (other == null) { 097 return this; 098 } 099 100 if (!(other instanceof ResourceOperationEventBuilder)) { 101 throw new IllegalStateException( 102 String.format("Cannot merge EventBuilders because they are different types <%s> and <%s>", 103 this.getClass(), other.getClass())); 104 } 105 106 final var otherCast = (ResourceOperationEventBuilder) other; 107 108 if (!this.fedoraId.equals(otherCast.fedoraId)) { 109 throw new IllegalStateException( 110 String.format("Cannot merge events because they are for different resources: <%s> and <%s>", 111 this, otherCast)); 112 } 113 114 this.types.addAll(otherCast.types); 115 this.resourceTypes.addAll(otherCast.resourceTypes); 116 117 if (this.date.isBefore(otherCast.date)) { 118 this.date = otherCast.date; 119 } 120 121 return this; 122 } 123 124 @Override 125 public EventBuilder withResourceTypes(final Set<String> resourceTypes) { 126 this.resourceTypes = Objects.requireNonNullElse(resourceTypes, new HashSet<>()); 127 return this; 128 } 129 130 @Override 131 public EventBuilder withBaseUrl(final String baseUrl) { 132 this.baseUrl = baseUrl; 133 return this; 134 } 135 136 @Override 137 public EventBuilder withUserAgent(final String userAgent) { 138 this.userAgent = userAgent; 139 return this; 140 } 141 142 @Override 143 public Event build() { 144 URI userUri = null; 145 if (userID != null) { 146 userUri = UserUtil.getUserURI(userID, userAgentBaseUri); 147 } 148 return new EventImpl(fedoraId, types, resourceTypes, userID, userUri, userAgent, baseUrl, date); 149 } 150 151 @Override 152 public String toString() { 153 return "ResourceOperationEventBuilder{" + 154 "fedoraId=" + fedoraId + 155 ", types=" + types + 156 ", resourceTypes=" + resourceTypes + 157 ", userID='" + userID + '\'' + 158 ", userAgent='" + userAgent + '\'' + 159 ", baseUrl='" + baseUrl + '\'' + 160 ", date=" + date + 161 '}'; 162 } 163 164}