001/** 002 * Copyright 2015 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fcrepo.kernel.impl.observer; 017 018import static com.codahale.metrics.MetricRegistry.name; 019import static com.google.common.base.Throwables.propagate; 020import static com.google.common.collect.Iterators.filter; 021import static com.google.common.collect.Iterators.transform; 022import static javax.jcr.observation.Event.NODE_ADDED; 023import static javax.jcr.observation.Event.NODE_MOVED; 024import static javax.jcr.observation.Event.NODE_REMOVED; 025import static javax.jcr.observation.Event.PROPERTY_ADDED; 026import static javax.jcr.observation.Event.PROPERTY_CHANGED; 027import static javax.jcr.observation.Event.PROPERTY_REMOVED; 028import static org.slf4j.LoggerFactory.getLogger; 029import org.fcrepo.metrics.RegistryService; 030 031import java.util.Iterator; 032 033import javax.annotation.PostConstruct; 034import javax.annotation.PreDestroy; 035import javax.inject.Inject; 036import javax.jcr.RepositoryException; 037import javax.jcr.Session; 038import javax.jcr.observation.Event; 039import javax.jcr.observation.EventListener; 040 041import org.fcrepo.kernel.observer.EventFilter; 042import org.fcrepo.kernel.observer.FedoraEvent; 043import org.fcrepo.kernel.observer.eventmappings.InternalExternalEventMapper; 044import org.modeshape.jcr.api.Repository; 045import org.slf4j.Logger; 046 047import com.codahale.metrics.Counter; 048import com.google.common.eventbus.EventBus; 049 050/** 051 * Simple JCR EventListener that filters JCR Events through a Fedora EventFilter 052 * and puts the resulting stream onto the internal Fedora EventBus as a stream 053 * of FedoraEvents. 054 * 055 * @author eddies 056 * @author ajs6f 057 * @since Feb 7, 2013 058 */ 059public class SimpleObserver implements EventListener { 060 061 private static final Logger LOGGER = getLogger(SimpleObserver.class); 062 063 /** 064 * A simple counter of events that pass through this observer 065 */ 066 static final Counter EVENT_COUNTER = 067 RegistryService.getInstance().getMetrics().counter(name(SimpleObserver.class, "onEvent")); 068 069 static final Integer EVENT_TYPES = NODE_ADDED + NODE_REMOVED + NODE_MOVED + PROPERTY_ADDED + PROPERTY_CHANGED 070 + PROPERTY_REMOVED; 071 072 @Inject 073 private Repository repository; 074 075 @Inject 076 private EventBus eventBus; 077 078 @Inject 079 private InternalExternalEventMapper eventMapper; 080 081 @Inject 082 private EventFilter eventFilter; 083 084 // THIS SESSION SHOULD NOT BE USED TO LOOK UP NODES 085 // it is used only to register and deregister this observer to the JCR 086 private Session session; 087 088 /** 089 * Register this observer with the JCR event listeners 090 * 091 * @throws RepositoryException if repository exception occurred 092 */ 093 @PostConstruct 094 public void buildListener() throws RepositoryException { 095 LOGGER.debug("Constructing an observer for JCR events..."); 096 session = repository.login(); 097 session.getWorkspace().getObservationManager() 098 .addEventListener(this, EVENT_TYPES, "/", true, null, null, false); 099 session.save(); 100 } 101 102 /** 103 * logout of the session 104 * 105 * @throws RepositoryException if repository exception occurred 106 */ 107 @PreDestroy 108 public void stopListening() throws RepositoryException { 109 LOGGER.debug("Destroying an observer for JCR events..."); 110 session.getWorkspace().getObservationManager().removeEventListener(this); 111 session.logout(); 112 } 113 114 /** 115 * Filter JCR events and transform them into our own FedoraEvents. 116 * 117 * @param events the JCR events 118 */ 119 @Override 120 public void onEvent(final javax.jcr.observation.EventIterator events) { 121 Session lookupSession = null; 122 try { 123 lookupSession = repository.login(); 124 125 @SuppressWarnings("unchecked") 126 final Iterator<Event> filteredEvents = filter(events, eventFilter.getFilter(lookupSession)); 127 final Iterator<FedoraEvent> publishableEvents = eventMapper.apply(filteredEvents); 128 final Iterator<FedoraEvent> namespacedEvents = 129 transform(publishableEvents, new GetNamespacedProperties(lookupSession)); 130 131 while (namespacedEvents.hasNext()) { 132 eventBus.post(namespacedEvents.next()); 133 EVENT_COUNTER.inc(); 134 } 135 } catch (final RepositoryException ex) { 136 throw propagate(ex); 137 } finally { 138 if (lookupSession != null) { 139 lookupSession.logout(); 140 } 141 } 142 } 143}