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.kernel.modeshape.observer.eventmappings;
019
020import static org.fcrepo.kernel.modeshape.utils.UncheckedFunction.uncheck;
021import static org.fcrepo.kernel.modeshape.observer.FedoraEventImpl.from;
022import static org.fcrepo.kernel.modeshape.observer.FedoraEventImpl.getResourceTypes;
023import static org.slf4j.LoggerFactory.getLogger;
024import static java.util.stream.Collectors.groupingBy;
025import static java.util.stream.Collectors.toSet;
026import static java.util.stream.Stream.empty;
027import static java.util.stream.Stream.of;
028
029import java.util.List;
030import java.util.function.Function;
031import java.util.stream.Stream;
032
033import javax.jcr.observation.Event;
034
035import org.fcrepo.kernel.api.observer.FedoraEvent;
036import org.fcrepo.kernel.modeshape.observer.FedoraEventImpl;
037
038import org.slf4j.Logger;
039
040/**
041 * Maps all JCR {@link Event}s concerning one JCR node to one {@link FedoraEvent}. Adds the types of those JCR events
042 * together to calculate the final type of the emitted FedoraEvent.
043 *
044 * @author ajs6f
045 * @author acoburn
046 * @since Feb 27, 2014
047 */
048public class AllNodeEventsOneEvent implements InternalExternalEventMapper {
049
050    private final static Logger LOGGER = getLogger(AllNodeEventsOneEvent.class);
051
052    /**
053     * Extracts an identifier from a JCR {@link Event} by building an id from nodepath and user to collapse multiple
054     * events from repository mutations
055     */
056    private static final Function<Event, String> EXTRACT_NODE_ID = uncheck(ev -> {
057            final FedoraEvent event = from(ev);
058            final String id = event.getPath() + "-" + event.getUserID();
059            LOGGER.debug("Sorting an event by identifier: {}", id);
060            return id;
061    });
062
063    @Override
064    public Stream<FedoraEvent> apply(final Stream<Event> events) {
065        // first, index all the events by path-userID and then flatMap over that list of values
066        // each of which returns either a singleton Stream or an empty Stream. The final result
067        // will be a concatenated Stream of FedoraEvent objects.
068        return events.collect(groupingBy(EXTRACT_NODE_ID)).entrySet().stream().flatMap(entry -> {
069            final List<Event> evts = entry.getValue();
070            if (!evts.isEmpty()) {
071                // build a FedoraEvent from the first JCR Event
072                final FedoraEvent fedoraEvent = from(evts.get(0));
073                evts.stream().skip(1).forEach(evt -> {
074                    // add types to the FedoraEvent from the subsequent JCR Events
075                    fedoraEvent.getTypes().add(FedoraEventImpl.valueOf(evt.getType()));
076                    fedoraEvent.getResourceTypes().addAll(getResourceTypes(evt).collect(toSet()));
077                });
078                return of(fedoraEvent);
079            }
080            return empty();
081        });
082    }
083}