001/*
002 * Copyright 2012-2018 the original author or authors.
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
017package org.springframework.boot.actuate.audit;
018
019import java.io.Serializable;
020import java.time.Instant;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024
025import com.fasterxml.jackson.annotation.JsonInclude;
026import com.fasterxml.jackson.annotation.JsonInclude.Include;
027
028import org.springframework.context.ApplicationEventPublisher;
029import org.springframework.context.ApplicationEventPublisherAware;
030import org.springframework.util.Assert;
031
032/**
033 * A value object representing an audit event: at a particular time, a particular user or
034 * agent carried out an action of a particular type. This object records the details of
035 * such an event.
036 * <p>
037 * Users can inject a {@link AuditEventRepository} to publish their own events or
038 * alternatively use Spring's {@link ApplicationEventPublisher} (usually obtained by
039 * implementing {@link ApplicationEventPublisherAware}) to publish AuditApplicationEvents
040 * (wrappers for AuditEvent).
041 *
042 * @author Dave Syer
043 * @see AuditEventRepository
044 */
045@JsonInclude(Include.NON_EMPTY)
046public class AuditEvent implements Serializable {
047
048        private final Instant timestamp;
049
050        private final String principal;
051
052        private final String type;
053
054        private final Map<String, Object> data;
055
056        /**
057         * Create a new audit event for the current time.
058         * @param principal the user principal responsible
059         * @param type the event type
060         * @param data the event data
061         */
062        public AuditEvent(String principal, String type, Map<String, Object> data) {
063                this(Instant.now(), principal, type, data);
064        }
065
066        /**
067         * Create a new audit event for the current time from data provided as name-value
068         * pairs.
069         * @param principal the user principal responsible
070         * @param type the event type
071         * @param data the event data in the form 'key=value' or simply 'key'
072         */
073        public AuditEvent(String principal, String type, String... data) {
074                this(Instant.now(), principal, type, convert(data));
075        }
076
077        /**
078         * Create a new audit event.
079         * @param timestamp the date/time of the event
080         * @param principal the user principal responsible
081         * @param type the event type
082         * @param data the event data
083         */
084        public AuditEvent(Instant timestamp, String principal, String type,
085                        Map<String, Object> data) {
086                Assert.notNull(timestamp, "Timestamp must not be null");
087                Assert.notNull(type, "Type must not be null");
088                this.timestamp = timestamp;
089                this.principal = (principal != null) ? principal : "";
090                this.type = type;
091                this.data = Collections.unmodifiableMap(data);
092        }
093
094        private static Map<String, Object> convert(String[] data) {
095                Map<String, Object> result = new HashMap<>();
096                for (String entry : data) {
097                        int index = entry.indexOf('=');
098                        if (index != -1) {
099                                result.put(entry.substring(0, index), entry.substring(index + 1));
100                        }
101                        else {
102                                result.put(entry, null);
103                        }
104                }
105                return result;
106        }
107
108        /**
109         * Returns the date/time that the event was logged.
110         * @return the timestamp
111         */
112        public Instant getTimestamp() {
113                return this.timestamp;
114        }
115
116        /**
117         * Returns the user principal responsible for the event or an empty String if the
118         * principal is not available.
119         * @return the principal
120         */
121        public String getPrincipal() {
122                return this.principal;
123        }
124
125        /**
126         * Returns the type of event.
127         * @return the event type
128         */
129        public String getType() {
130                return this.type;
131        }
132
133        /**
134         * Returns the event data.
135         * @return the event data
136         */
137        public Map<String, Object> getData() {
138                return this.data;
139        }
140
141        @Override
142        public String toString() {
143                return "AuditEvent [timestamp=" + this.timestamp + ", principal=" + this.principal
144                                + ", type=" + this.type + ", data=" + this.data + "]";
145        }
146
147}