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.event.serialization; 019 020import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel; 021import static org.apache.jena.rdf.model.ResourceFactory.createProperty; 022import static org.apache.jena.rdf.model.ResourceFactory.createResource; 023import static org.apache.jena.vocabulary.DCTerms.identifier; 024import static org.apache.jena.vocabulary.DCTerms.isPartOf; 025import static org.apache.jena.vocabulary.RDF.type; 026import static java.nio.charset.StandardCharsets.UTF_8; 027import static java.time.Instant.ofEpochMilli; 028import static org.fcrepo.kernel.api.RdfLexicon.EVENT_NAMESPACE; 029import static org.fcrepo.kernel.api.RdfLexicon.PROV_NAMESPACE; 030import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE; 031import static org.fcrepo.kernel.api.observer.OptionalValues.BASE_URL; 032import static org.fcrepo.kernel.api.observer.OptionalValues.USER_AGENT; 033import static org.junit.Assert.assertEquals; 034import static org.junit.Assert.assertTrue; 035import static org.mockito.Mockito.when; 036 037import java.io.ByteArrayInputStream; 038import java.io.IOException; 039import java.time.Instant; 040import java.util.ArrayList; 041import java.util.HashMap; 042import java.util.HashSet; 043import java.util.List; 044import java.util.Map; 045import java.util.Set; 046import java.util.concurrent.atomic.AtomicInteger; 047 048import com.fasterxml.jackson.databind.JsonNode; 049import com.fasterxml.jackson.databind.ObjectMapper; 050import org.apache.jena.rdf.model.Model; 051import org.apache.jena.rdf.model.Resource; 052import org.apache.jena.rdf.model.SimpleSelector; 053import org.fcrepo.kernel.api.observer.EventType; 054import org.fcrepo.kernel.api.observer.FedoraEvent; 055import org.junit.Before; 056import org.junit.Test; 057import org.junit.runner.RunWith; 058import org.mockito.Mock; 059import org.mockito.runners.MockitoJUnitRunner; 060 061/** 062 * <p>FedoraEventTest class.</p> 063 * 064 * @author acoburn 065 */ 066@RunWith(MockitoJUnitRunner.class) 067public class JsonLdEventTest { 068 069 private static String FOAF_NAMESPACE = "http://xmlns.com/foaf/0.1/"; 070 071 @Mock 072 private FedoraEvent mockEvent; 073 074 private String baseUrl = "http://localhost:8080/fcrepo/rest"; 075 076 private String path = "/path/to/resource"; 077 078 private Instant timestamp = ofEpochMilli(1465919304000L); 079 080 @Before 081 public void setUp() { 082 final Set<EventType> typeSet = new HashSet<>(); 083 typeSet.add(EventType.RESOURCE_MODIFICATION); 084 final Set<String> resourceTypeSet = new HashSet<>(); 085 resourceTypeSet.add(REPOSITORY_NAMESPACE + "Resource"); 086 resourceTypeSet.add(REPOSITORY_NAMESPACE + "Container"); 087 resourceTypeSet.add("http://example.com/SampleType"); 088 final Map<String, String> auxInfo = new HashMap<>(); 089 auxInfo.put(BASE_URL, baseUrl); 090 auxInfo.put(USER_AGENT, "fcrepo-client/1.0"); 091 when(mockEvent.getTypes()).thenReturn(typeSet); 092 when(mockEvent.getResourceTypes()).thenReturn(resourceTypeSet); 093 when(mockEvent.getPath()).thenReturn(path); 094 when(mockEvent.getUserID()).thenReturn("fedo raadmin"); 095 when(mockEvent.getDate()).thenReturn(timestamp); 096 when(mockEvent.getEventID()).thenReturn("urn:uuid:some-event"); 097 when(mockEvent.getInfo()).thenReturn(auxInfo); 098 } 099 100 @Test 101 public void testJsonSerializationAsModel() { 102 final EventSerializer serializer = new JsonLDSerializer(); 103 final String json = serializer.serialize(mockEvent); 104 final Model model = createDefaultModel(); 105 model.read(new ByteArrayInputStream(json.getBytes(UTF_8)), baseUrl + path, "JSON-LD"); 106 107 final Resource subject = createResource(baseUrl + path); 108 final Resource blankNode = null; 109 110 assertTrue(model.contains(subject, type, createResource(REPOSITORY_NAMESPACE + "Resource"))); 111 assertTrue(model.contains(subject, type, createResource(REPOSITORY_NAMESPACE + "Container"))); 112 assertTrue(model.contains(subject, type, createResource(PROV_NAMESPACE + "Entity"))); 113 assertTrue(model.contains(subject, type, createResource("http://example.com/SampleType"))); 114 assertTrue(model.contains(subject, isPartOf, createResource(baseUrl))); 115 assertTrue(model.contains(subject, createProperty(PROV_NAMESPACE + "wasGeneratedBy"))); 116 assertTrue(model.contains(subject, createProperty(PROV_NAMESPACE + "wasAttributedTo"))); 117 118 final AtomicInteger activities = new AtomicInteger(); 119 model.listStatements(new SimpleSelector(subject, createProperty(PROV_NAMESPACE + "wasGeneratedBy"), blankNode)) 120 .forEachRemaining(statement -> { 121 final Resource r = statement.getResource(); 122 assertTrue(r.hasProperty(type, createResource(EVENT_NAMESPACE + "ResourceModification"))); 123 assertTrue(r.hasProperty(type, createResource(PROV_NAMESPACE + "Activity"))); 124 assertTrue(r.hasProperty(identifier, createResource("urn:uuid:some-event"))); 125 activities.incrementAndGet(); 126 }); 127 assertEquals(activities.get(), 1); 128 129 final AtomicInteger agents = new AtomicInteger(); 130 model.listStatements(new SimpleSelector(subject, createProperty(PROV_NAMESPACE + "wasAttributedTo"), blankNode)) 131 .forEachRemaining(statement -> { 132 final Resource r = statement.getResource(); 133 if (r.hasProperty(type, createResource(PROV_NAMESPACE + "Person"))) { 134 assertTrue(r.hasProperty(type, createResource(PROV_NAMESPACE + "Person"))); 135 assertTrue(r.hasProperty(createProperty(FOAF_NAMESPACE + "name"), "fedo raadmin")); 136 } else { 137 assertTrue(r.hasProperty(type, createResource(PROV_NAMESPACE + "SoftwareAgent"))); 138 assertTrue(r.hasProperty(createProperty(FOAF_NAMESPACE + "name"), "fcrepo-client/1.0")); 139 } 140 agents.incrementAndGet(); 141 }); 142 assertEquals(agents.get(), 2); 143 assertEquals(1, 1); 144 } 145 146 @Test 147 public void testJsonSerializationAsJson() throws IOException { 148 final EventSerializer serializer = new JsonLDSerializer(); 149 final String json = serializer.serialize(mockEvent); 150 151 final ObjectMapper mapper = new ObjectMapper(); 152 final JsonNode node = mapper.readTree(json); 153 assertTrue(node.has("@context")); 154 assertTrue(node.has("id")); 155 assertEquals(node.get("id").textValue(), baseUrl + path); 156 final List<String> types = new ArrayList<>(); 157 node.get("type").elements().forEachRemaining(n -> { 158 types.add(n.textValue()); 159 }); 160 assertEquals(types.size(), 4); 161 assertTrue(types.contains(REPOSITORY_NAMESPACE + "Resource")); 162 assertTrue(types.contains(REPOSITORY_NAMESPACE + "Container")); 163 assertTrue(types.contains(PROV_NAMESPACE + "Entity")); 164 assertTrue(types.contains("http://example.com/SampleType")); 165 assertTrue(node.has("isPartOf")); 166 assertEquals(node.get("isPartOf").textValue(), baseUrl); 167 168 // verify prov:Activity node 169 assertTrue(node.has("wasGeneratedBy")); 170 final JsonNode activity = node.get("wasGeneratedBy"); 171 final List<String> activityTypes = new ArrayList<>(); 172 assertTrue(activity.has("type")); 173 activity.get("type").elements().forEachRemaining(n -> { 174 activityTypes.add(n.textValue()); 175 }); 176 assertEquals(activityTypes.size(), 2); 177 assertTrue(activityTypes.contains(EVENT_NAMESPACE + "ResourceModification")); 178 assertTrue(activityTypes.contains(PROV_NAMESPACE + "Activity")); 179 assertTrue(activity.has("atTime")); 180 assertTrue(activity.has("identifier")); 181 assertEquals(activity.get("atTime").textValue(), timestamp.toString()); 182 assertEquals(activity.get("identifier").textValue(), "urn:uuid:some-event"); 183 184 // verify prov:Agent node 185 assertTrue(node.has("wasAttributedTo")); 186 final AtomicInteger agents = new AtomicInteger(); 187 node.get("wasAttributedTo").elements().forEachRemaining(n -> { 188 assertTrue(n.has("type")); 189 assertTrue(n.has("name")); 190 if (n.get("type").textValue().equals(PROV_NAMESPACE + "Person")) { 191 assertEquals(n.get("type").textValue(), PROV_NAMESPACE + "Person"); 192 assertEquals(n.get("name").textValue(), "fedo raadmin"); 193 } else { 194 assertEquals(n.get("type").textValue(), PROV_NAMESPACE + "SoftwareAgent"); 195 assertEquals(n.get("name").textValue(), "fcrepo-client/1.0"); 196 } 197 agents.incrementAndGet(); 198 }); 199 assertEquals(agents.get(), 2); 200 } 201}