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.modeshape.observer; 017 018import static com.google.common.base.MoreObjects.toStringHelper; 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.collect.Sets.union; 021import static org.fcrepo.kernel.api.utils.EventType.valueOf; 022import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT; 023import static java.util.Collections.singleton; 024import static java.util.stream.Collectors.toList; 025import static javax.jcr.observation.Event.PROPERTY_ADDED; 026import static javax.jcr.observation.Event.PROPERTY_CHANGED; 027import static javax.jcr.observation.Event.PROPERTY_REMOVED; 028 029import java.util.Arrays; 030import java.util.HashSet; 031import java.util.List; 032import java.util.Set; 033 034import javax.jcr.RepositoryException; 035import javax.jcr.observation.Event; 036 037import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 038import org.fcrepo.kernel.api.observer.FedoraEvent; 039import org.fcrepo.kernel.api.services.functions.HierarchicalIdentifierSupplier; 040import org.fcrepo.kernel.api.services.functions.UniqueValueSupplier; 041import org.fcrepo.kernel.api.utils.EventType; 042 043/** 044 * A very simple abstraction to prevent event-driven machinery downstream from the repository from relying directly 045 * on a JCR interface {@link Event}. Can represent either a single JCR event or several. 046 * 047 * @author ajs6f 048 * @since Feb 19, 2013 049 */ 050public class FedoraEventImpl implements FedoraEvent { 051 052 private Event e; 053 private final String eventID; 054 055 private Set<EventType> eventTypes = new HashSet<>(); 056 private Set<String> eventProperties = new HashSet<>(); 057 private static final List<Integer> PROPERTY_TYPES = Arrays.asList(PROPERTY_ADDED, PROPERTY_CHANGED, 058 PROPERTY_REMOVED); 059 060 private static final UniqueValueSupplier pidMinter = new DefaultPathMinter(); 061 062 /** 063 * Wrap a JCR Event with our FedoraEvent decorators 064 * 065 * @param e the JCR event 066 */ 067 public FedoraEventImpl(final Event e) { 068 checkArgument(e != null, "null cannot support a FedoraEvent!"); 069 eventID = pidMinter.get(); 070 this.e = e; 071 } 072 073 /** 074 * Create a FedoraEvent from an existing FedoraEvent object 075 * Note: Only the wrapped JCR event is passed on to the new object. 076 * 077 * @param e the given fedora event 078 */ 079 public FedoraEventImpl(final FedoraEvent e) { 080 checkArgument(e != null, "null cannot support a FedoraEvent!"); 081 eventID = e.getEventID(); 082 this.e = ((FedoraEventImpl)e).e; 083 } 084 085 /** 086 * @return the event types of the underlying JCR {@link Event}s 087 */ 088 @Override 089 public Set<EventType> getTypes() { 090 final EventType type = valueOf(e.getType()); 091 return eventTypes != null ? union(singleton(type), eventTypes) : singleton(type); 092 } 093 094 /** 095 * @param type the type 096 * @return this object for continued use 097 */ 098 @Override 099 public FedoraEvent addType(final EventType type) { 100 eventTypes.add(type); 101 return this; 102 } 103 104 /** 105 * @return the property names of the underlying JCR property {@link Event}s 106 **/ 107 @Override 108 public Set<String> getProperties() { 109 return eventProperties; 110 } 111 112 /** 113 * Add a property name to this event 114 * @param property property name 115 * @return this object for continued use 116 **/ 117 @Override 118 public FedoraEvent addProperty( final String property ) { 119 eventProperties.add(property); 120 return this; 121 } 122 123 /** 124 * @return the path of the underlying JCR {@link Event}s 125 */ 126 @Override 127 public String getPath() { 128 return getPath(e); 129 } 130 131 /** 132 * Get the path of the node related to this event (removing property names 133 * from the end of property nodes). 134 * @param e JCR Event 135 * @return the node path for this event 136 **/ 137 public static String getPath(final Event e) { 138 try { 139 final String path; 140 if (PROPERTY_TYPES.contains(e.getType())) { 141 path = e.getPath().substring(0, e.getPath().lastIndexOf("/")); 142 } else { 143 path = e.getPath(); 144 } 145 return path.replaceAll("/" + JCR_CONTENT, ""); 146 } catch (RepositoryException e1) { 147 throw new RepositoryRuntimeException("Error getting event path!", e1); 148 } 149 } 150 151 /** 152 * @return the user ID of the underlying JCR {@link Event}s 153 */ 154 @Override 155 public String getUserID() { 156 return e.getUserID(); 157 } 158 159 /** 160 * @return the user data of the underlying JCR {@link Event}s 161 */ 162 @Override 163 public String getUserData() { 164 try { 165 return e.getUserData(); 166 } catch (RepositoryException e1) { 167 throw new RepositoryRuntimeException("Error getting event userData!", e1); 168 } 169 } 170 171 /** 172 * @return the date of the underlying JCR {@link Event}s 173 */ 174 @Override 175 public long getDate() { 176 try { 177 return e.getDate(); 178 } catch (RepositoryException e1) { 179 throw new RepositoryRuntimeException("Error getting event date!", e1); 180 } 181 } 182 183 /** 184 * Get the event ID. 185 * @return Event identifier to use for building event URIs (e.g., in an external triplestore). 186 **/ 187 @Override 188 public String getEventID() { 189 return eventID; 190 } 191 192 @Override 193 public String toString() { 194 195 return toStringHelper(this) 196 .add("Event types:", String.join(",", getTypes().stream() 197 .map(EventType::getName) 198 .collect(toList()))) 199 .add("Event properties:", String.join(",", eventProperties)) 200 .add("Path:", getPath()) 201 .add("Date: ", getDate()).toString(); 202 } 203 204 private static class DefaultPathMinter implements HierarchicalIdentifierSupplier { } 205}