/*
* Licensed to DuraSpace under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* DuraSpace licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fcrepo.event.serialization;
import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
import static org.apache.jena.rdf.model.ResourceFactory.createProperty;
import static org.apache.jena.rdf.model.ResourceFactory.createResource;
import static org.apache.jena.vocabulary.DCTerms.identifier;
import static org.apache.jena.vocabulary.DCTerms.isPartOf;
import static org.apache.jena.vocabulary.RDF.type;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.time.Instant.ofEpochMilli;
import static org.fcrepo.kernel.api.RdfLexicon.EVENT_NAMESPACE;
import static org.fcrepo.kernel.api.RdfLexicon.PROV_NAMESPACE;
import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.fcrepo.kernel.api.observer.OptionalValues.BASE_URL;
import static org.fcrepo.kernel.api.observer.OptionalValues.USER_AGENT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.SimpleSelector;
import org.fcrepo.kernel.api.observer.EventType;
import org.fcrepo.kernel.api.observer.FedoraEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
* <p>FedoraEventTest class.</p>
*
* @author acoburn
*/
@RunWith(MockitoJUnitRunner.class)
public class JsonLdEventTest {
private static String FOAF_NAMESPACE = "http://xmlns.com/foaf/0.1/";
@Mock
private FedoraEvent mockEvent;
private String baseUrl = "http://localhost:8080/fcrepo/rest";
private String path = "/path/to/resource";
private Instant timestamp = ofEpochMilli(1465919304000L);
@Before
public void setUp() {
final Set<EventType> typeSet = new HashSet<>();
typeSet.add(EventType.RESOURCE_MODIFICATION);
final Set<String> resourceTypeSet = new HashSet<>();
resourceTypeSet.add(REPOSITORY_NAMESPACE + "Resource");
resourceTypeSet.add(REPOSITORY_NAMESPACE + "Container");
resourceTypeSet.add("http://example.com/SampleType");
final Map<String, String> auxInfo = new HashMap<>();
auxInfo.put(BASE_URL, baseUrl);
auxInfo.put(USER_AGENT, "fcrepo-client/1.0");
when(mockEvent.getTypes()).thenReturn(typeSet);
when(mockEvent.getResourceTypes()).thenReturn(resourceTypeSet);
when(mockEvent.getPath()).thenReturn(path);
when(mockEvent.getUserID()).thenReturn("fedo raadmin");
when(mockEvent.getDate()).thenReturn(timestamp);
when(mockEvent.getEventID()).thenReturn("urn:uuid:some-event");
when(mockEvent.getInfo()).thenReturn(auxInfo);
}
@Test
public void testJsonSerializationAsModel() {
final EventSerializer serializer = new JsonLDSerializer();
final String json = serializer.serialize(mockEvent);
final Model model = createDefaultModel();
model.read(new ByteArrayInputStream(json.getBytes(UTF_8)), baseUrl + path, "JSON-LD");
final Resource subject = createResource(baseUrl + path);
final Resource blankNode = null;
assertTrue(model.contains(subject, type, createResource(REPOSITORY_NAMESPACE + "Resource")));
assertTrue(model.contains(subject, type, createResource(REPOSITORY_NAMESPACE + "Container")));
assertTrue(model.contains(subject, type, createResource(PROV_NAMESPACE + "Entity")));
assertTrue(model.contains(subject, type, createResource("http://example.com/SampleType")));
assertTrue(model.contains(subject, isPartOf, createResource(baseUrl)));
assertTrue(model.contains(subject, createProperty(PROV_NAMESPACE + "wasGeneratedBy")));
assertTrue(model.contains(subject, createProperty(PROV_NAMESPACE + "wasAttributedTo")));
final AtomicInteger activities = new AtomicInteger();
model.listStatements(new SimpleSelector(subject, createProperty(PROV_NAMESPACE + "wasGeneratedBy"), blankNode))
.forEachRemaining(statement -> {
final Resource r = statement.getResource();
assertTrue(r.hasProperty(type, createResource(EVENT_NAMESPACE + "ResourceModification")));
assertTrue(r.hasProperty(type, createResource(PROV_NAMESPACE + "Activity")));
assertTrue(r.hasProperty(identifier, createResource("urn:uuid:some-event")));
activities.incrementAndGet();
});
assertEquals(activities.get(), 1);
final AtomicInteger agents = new AtomicInteger();
model.listStatements(new SimpleSelector(subject, createProperty(PROV_NAMESPACE + "wasAttributedTo"), blankNode))
.forEachRemaining(statement -> {
final Resource r = statement.getResource();
if (r.hasProperty(type, createResource(PROV_NAMESPACE + "Person"))) {
assertTrue(r.hasProperty(type, createResource(PROV_NAMESPACE + "Person")));
assertTrue(r.hasProperty(createProperty(FOAF_NAMESPACE + "name"), "fedo raadmin"));
} else {
assertTrue(r.hasProperty(type, createResource(PROV_NAMESPACE + "SoftwareAgent")));
assertTrue(r.hasProperty(createProperty(FOAF_NAMESPACE + "name"), "fcrepo-client/1.0"));
}
agents.incrementAndGet();
});
assertEquals(agents.get(), 2);
assertEquals(1, 1);
}
@Test
public void testJsonSerializationAsJson() throws IOException {
final EventSerializer serializer = new JsonLDSerializer();
final String json = serializer.serialize(mockEvent);
final ObjectMapper mapper = new ObjectMapper();
final JsonNode node = mapper.readTree(json);
assertTrue(node.has("@context"));
assertTrue(node.has("id"));
assertEquals(node.get("id").textValue(), baseUrl + path);
final List<String> types = new ArrayList<>();
node.get("type").elements().forEachRemaining(n -> {
types.add(n.textValue());
});
assertEquals(types.size(), 4);
assertTrue(types.contains(REPOSITORY_NAMESPACE + "Resource"));
assertTrue(types.contains(REPOSITORY_NAMESPACE + "Container"));
assertTrue(types.contains(PROV_NAMESPACE + "Entity"));
assertTrue(types.contains("http://example.com/SampleType"));
assertTrue(node.has("isPartOf"));
assertEquals(node.get("isPartOf").textValue(), baseUrl);
// verify prov:Activity node
assertTrue(node.has("wasGeneratedBy"));
final JsonNode activity = node.get("wasGeneratedBy");
final List<String> activityTypes = new ArrayList<>();
assertTrue(activity.has("type"));
activity.get("type").elements().forEachRemaining(n -> {
activityTypes.add(n.textValue());
});
assertEquals(activityTypes.size(), 2);
assertTrue(activityTypes.contains(EVENT_NAMESPACE + "ResourceModification"));
assertTrue(activityTypes.contains(PROV_NAMESPACE + "Activity"));
assertTrue(activity.has("atTime"));
assertTrue(activity.has("identifier"));
assertEquals(activity.get("atTime").textValue(), timestamp.toString());
assertEquals(activity.get("identifier").textValue(), "urn:uuid:some-event");
// verify prov:Agent node
assertTrue(node.has("wasAttributedTo"));
final AtomicInteger agents = new AtomicInteger();
node.get("wasAttributedTo").elements().forEachRemaining(n -> {
assertTrue(n.has("type"));
assertTrue(n.has("name"));
if (n.get("type").textValue().equals(PROV_NAMESPACE + "Person")) {
assertEquals(n.get("type").textValue(), PROV_NAMESPACE + "Person");
assertEquals(n.get("name").textValue(), "fedo raadmin");
} else {
assertEquals(n.get("type").textValue(), PROV_NAMESPACE + "SoftwareAgent");
assertEquals(n.get("name").textValue(), "fcrepo-client/1.0");
}
agents.incrementAndGet();
});
assertEquals(agents.get(), 2);
}
}