001/* 002 * (C) Copyright 2006-2018 Nuxeo (http://nuxeo.com/) and others. 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 * 016 * Contributors: 017 * Julien Anguenot 018 * Thierry Delprat 019 * Florent Guillaume 020 */ 021 022package org.nuxeo.ecm.platform.audit.impl; 023 024import java.io.IOException; 025import java.util.Date; 026import java.util.HashMap; 027import java.util.Map; 028 029import javax.persistence.CascadeType; 030import javax.persistence.Column; 031import javax.persistence.Entity; 032import javax.persistence.GeneratedValue; 033import javax.persistence.GenerationType; 034import javax.persistence.Id; 035import javax.persistence.JoinColumn; 036import javax.persistence.JoinTable; 037import javax.persistence.MapKey; 038import javax.persistence.NamedQueries; 039import javax.persistence.NamedQuery; 040import javax.persistence.OneToMany; 041import javax.persistence.Table; 042import javax.persistence.Temporal; 043import javax.persistence.TemporalType; 044import javax.persistence.Transient; 045 046import org.apache.commons.lang3.builder.ToStringBuilder; 047import org.nuxeo.ecm.core.api.DocumentModel; 048import org.nuxeo.ecm.core.api.DocumentRef; 049import org.nuxeo.ecm.platform.audit.api.ExtendedInfo; 050import org.nuxeo.ecm.platform.audit.api.LogEntry; 051import org.nuxeo.ecm.platform.audit.api.comment.UIAuditComment; 052import org.nuxeo.ecm.platform.audit.io.ExtendedInfoDeserializer; 053import org.nuxeo.ecm.platform.audit.io.ExtendedInfoSerializer; 054 055import com.fasterxml.jackson.annotation.JsonProperty; 056import com.fasterxml.jackson.core.JsonGenerator; 057import com.fasterxml.jackson.databind.JsonSerializer; 058import com.fasterxml.jackson.databind.SerializerProvider; 059import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 060import com.fasterxml.jackson.databind.annotation.JsonSerialize; 061 062/** 063 * Log entry implementation. 064 */ 065@Entity(name = "LogEntry") 066@NamedQueries({ 067 @NamedQuery(name = "LogEntry.removeByEventIdAndPath", query = "delete LogEntry log where log.eventId = :eventId and log.docPath like :pathPattern"), 068 @NamedQuery(name = "LogEntry.findByDocument", query = "from LogEntry log where log.docUUID=:docUUID ORDER BY log.eventDate DESC"), 069 @NamedQuery(name = "LogEntry.findByDocumentAndRepository", query = "from LogEntry log where log.docUUID=:docUUID and log.repositoryId=:repositoryId ORDER BY log.eventDate DESC"), 070 @NamedQuery(name = "LogEntry.findAll", query = "from LogEntry log order by log.eventDate DESC"), 071 @NamedQuery(name = "LogEntry.findByEventIdAndPath", query = "from LogEntry log where log.eventId=:eventId and log.docPath LIKE :pathPattern"), 072 @NamedQuery(name = "LogEntry.findByHavingExtendedInfo", query = "from LogEntry log where log.extendedInfos['one'] is not null order by log.eventDate DESC"), 073 @NamedQuery(name = "LogEntry.countEventsById", query = "select count(log.eventId) from LogEntry log where log.eventId=:eventId"), 074 @NamedQuery(name = "LogEntry.findEventIds", query = "select distinct log.eventId from LogEntry log") }) 075@Table(name = "NXP_LOGS") 076public class LogEntryImpl implements LogEntry { 077 078 @JsonProperty("entity-type") 079 protected String entityType; 080 081 private static final long serialVersionUID = 3037187381843636097L; 082 083 private long id; 084 085 private String principalName; 086 087 private String eventId; 088 089 private Date eventDate; 090 091 private Date logDate; 092 093 private String docUUID; 094 095 private String docType; 096 097 private String docPath; 098 099 private String category; 100 101 private String comment; 102 103 private String docLifeCycle; 104 105 private String repositoryId; 106 107 protected transient UIAuditComment uiComment; 108 109 private Map<String, ExtendedInfoImpl> extendedInfos = new HashMap<String, ExtendedInfoImpl>(); 110 111 /** 112 * @return the log identifier 113 */ 114 @Override 115 @Id 116 @GeneratedValue(strategy = GenerationType.AUTO) 117 @Column(name = "LOG_ID", nullable = false, columnDefinition = "integer") 118 public long getId() { 119 return id; 120 } 121 122 @Override 123 public void setId(long id) { 124 this.id = id; 125 } 126 127 /** 128 * Returns the name of the principal who originated the log entry. 129 * 130 * @return the name of the principal who originated the log entry 131 */ 132 @Override 133 @Column(name = "LOG_PRINCIPAL_NAME") 134 public String getPrincipalName() { 135 return principalName; 136 } 137 138 @Override 139 public void setPrincipalName(String principalName) { 140 this.principalName = principalName; 141 } 142 143 /** 144 * Returns the identifier of the event that originated the log entry. 145 * 146 * @return the identifier of the event that originated the log entry 147 */ 148 @Override 149 @Column(name = "LOG_EVENT_ID", nullable = false) 150 @MapKey(name = "logKey") 151 public String getEventId() { 152 return eventId; 153 } 154 155 @Override 156 public void setEventId(String eventId) { 157 this.eventId = eventId; 158 } 159 160 /** 161 * Returns the date of the event that originated the log entry. 162 * 163 * @return the date of the event that originated the log entry 164 */ 165 @Override 166 @Temporal(TemporalType.TIMESTAMP) 167 @JsonSerialize(using = DateSerializer.class) 168 @Column(name = "LOG_EVENT_DATE") 169 public Date getEventDate() { 170 return eventDate; 171 } 172 173 @Override 174 public void setEventDate(Date eventDate) { 175 this.eventDate = eventDate; 176 } 177 178 /** 179 * @return the date of the log insertion: this up to max transaction timeout later than eventDate. This date is 180 * useful for services such as Nuxeo Drive that need fine grained incremental near-monotonic access to the 181 * audit log. 182 * @since 5.7 183 * @since 5.6-HF16 184 */ 185 @Override 186 @Temporal(TemporalType.TIMESTAMP) 187 @JsonSerialize(using = DateSerializer.class) 188 @Column(name = "LOG_DATE") 189 public Date getLogDate() { 190 return logDate; 191 } 192 193 @Override 194 public void setLogDate(Date logDate) { 195 this.logDate = logDate; 196 } 197 198 /** 199 * Returns the doc UUID related to the log entry. 200 * <p> 201 * It might be null if the event that originated the event is noe bound to any document. 202 * 203 * @return the doc UUID related to the log entry. 204 */ 205 @Override 206 @Column(name = "LOG_DOC_UUID") 207 public String getDocUUID() { 208 return docUUID; 209 } 210 211 @Override 212 public void setDocUUID(String docUUID) { 213 this.docUUID = docUUID; 214 } 215 216 @Override 217 public void setDocUUID(DocumentRef docRef) { 218 switch (docRef.type()) { 219 case DocumentRef.ID: 220 docUUID = (String) docRef.reference(); 221 break; 222 case DocumentRef.INSTANCE: 223 docUUID = ((DocumentModel) docRef.reference()).getId(); 224 break; 225 default: 226 throw new IllegalArgumentException("not an id reference " + docRef); 227 } 228 } 229 230 /** 231 * Returns the doc path related to the log entry. 232 * <p> 233 * It might be null if the event that originated the event is noe bound to any document. 234 * 235 * @return the doc path related to the log entry. 236 */ 237 @Override 238 @Column(name = "LOG_DOC_PATH", length = 1024) 239 public String getDocPath() { 240 return docPath; 241 } 242 243 @Override 244 public void setDocPath(String docPath) { 245 this.docPath = docPath; 246 } 247 248 /** 249 * Returns the doc type related to the log entry. 250 * <p> 251 * It might be null if the event that originated the event is not bound to any document. 252 * 253 * @return the doc type related to the log entry. 254 */ 255 @Override 256 @Column(name = "LOG_DOC_TYPE") 257 public String getDocType() { 258 return docType; 259 } 260 261 @Override 262 public void setDocType(String docType) { 263 this.docType = docType; 264 } 265 266 /** 267 * Returns the category for this log entry. 268 * <p> 269 * This is defined at client level. Categories are not restricted in any ways. 270 * 271 * @return the category for this log entry. 272 */ 273 @Override 274 @Column(name = "LOG_EVENT_CATEGORY") 275 public String getCategory() { 276 return category; 277 } 278 279 @Override 280 public void setCategory(String category) { 281 this.category = category; 282 } 283 284 /** 285 * Returns the associated comment for this log entry. 286 * 287 * @return the associated comment for this log entry 288 */ 289 @Override 290 @Column(name = "LOG_EVENT_COMMENT", length = 1024) 291 public String getComment() { 292 return comment; 293 } 294 295 @Override 296 public void setComment(String comment) { 297 this.comment = comment; 298 } 299 300 /** 301 * Return the life cycle if the document related to the log entry. 302 * <p> 303 * It might be null if the event that originated the event is noe bound to any document. 304 * 305 * @return the life cycle if the document related to the log entry. 306 */ 307 @Override 308 @Column(name = "LOG_DOC_LIFE_CYCLE") 309 public String getDocLifeCycle() { 310 return docLifeCycle; 311 } 312 313 @Override 314 public void setDocLifeCycle(String docLifeCycle) { 315 this.docLifeCycle = docLifeCycle; 316 } 317 318 /** 319 * Returns the repository id related to the log entry. 320 * 321 * @return the repository id 322 */ 323 @Override 324 @Column(name = "LOG_REPO_ID") 325 public String getRepositoryId() { 326 return repositoryId; 327 } 328 329 @Override 330 public void setRepositoryId(String repositoryId) { 331 this.repositoryId = repositoryId; 332 } 333 334 // public Map<String, ExtendedInfoImpl> getExtendedInfosImpl() { 335 // return extendedInfos; 336 // } 337 // 338 // public void setExtendedInfosImpl(Map<String, ExtendedInfoImpl> infos) { 339 // extendedInfos = infos; 340 // } 341 342 @Override 343 @JsonProperty("extended") 344 @JsonSerialize(keyAs = String.class, contentUsing = ExtendedInfoSerializer.class) 345 @OneToMany(cascade = CascadeType.ALL, targetEntity = ExtendedInfoImpl.class) 346 @JoinTable(name = "NXP_LOGS_MAPEXTINFOS", joinColumns = { @JoinColumn(name = "LOG_FK") }, inverseJoinColumns = { 347 @JoinColumn(name = "INFO_FK") }) 348 @org.hibernate.annotations.MapKey(columns = { @Column(name = "mapkey", nullable = false) }) 349 public Map<String, ExtendedInfo> getExtendedInfos() { 350 return (Map) extendedInfos; 351 // return (Map)getExtendedInfosImpl(); 352 } 353 354 @Override 355 @JsonDeserialize(keyAs = String.class, contentUsing = ExtendedInfoDeserializer.class) 356 public void setExtendedInfos(Map<String, ExtendedInfo> infos) { 357 extendedInfos = (Map) infos; 358 // setExtendedInfosImpl((Map)infos); 359 } 360 361 @Override 362 public String toString() { 363 return ToStringBuilder.reflectionToString(this); 364 } 365 366 @Transient 367 @Override 368 public UIAuditComment getPreprocessedComment() { 369 return uiComment; 370 } 371 372 @Override 373 public void setPreprocessedComment(UIAuditComment uiComment) { 374 this.uiComment = uiComment; 375 } 376 377 /** 378 * Specific date serializer to have compliant dates with both current and 8.10 Elasticsearch mapping 379 * 380 * @since 9.3 381 */ 382 static class DateSerializer extends JsonSerializer<Date> { 383 384 public DateSerializer() { 385 } 386 387 @Override 388 public void serialize(Date date, JsonGenerator jg, SerializerProvider serializers) throws IOException { 389 jg.writeObject(date.toInstant().toString()); 390 } 391 } 392 393}