/
EventFieldMetadata.java
197 lines (177 loc) · 7.04 KB
/
EventFieldMetadata.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package com.proofpoint.event.client;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.codehaus.jackson.JsonGenerator;
import org.joda.time.DateTime;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Objects.firstNonNull;
import static com.proofpoint.event.client.EventDataType.validateFieldValueType;
class EventFieldMetadata
{
public static final Comparator<EventFieldMetadata> NAME_COMPARATOR = new Comparator<EventFieldMetadata>()
{
public int compare(EventFieldMetadata a, EventFieldMetadata b)
{
return a.name.compareTo(b.name);
}
};
public static enum ContainerType
{
ITERABLE, MAP, MULTIMAP;
@Override
public String toString()
{
return name().toLowerCase();
}
}
private final String name;
private final String v1Name;
private final Method method;
private final EventDataType eventDataType;
private final EventTypeMetadata<?> nestedType;
private final ContainerType containerType;
EventFieldMetadata(String name, String v1Name, Method method, EventDataType eventDataType, EventTypeMetadata<?> nestedType, ContainerType containerType)
{
Preconditions.checkArgument((eventDataType != null) || (nestedType != null), "both eventDataType and nestedType are null");
Preconditions.checkArgument((eventDataType == null) || (nestedType == null), "both eventDataType and nestedType are set");
this.name = name;
this.v1Name = v1Name;
this.method = method;
this.eventDataType = eventDataType;
this.nestedType = nestedType;
this.containerType = containerType;
}
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") // IDEA-74322
private Object getValue(Object event)
throws InvalidEventException
{
try {
return method.invoke(event);
}
catch (Exception e) {
throw new InvalidEventException(firstNonNull(e.getCause(), e),
"Unable to get value of event field %s: Exception occurred while invoking [%s]", name, method.toGenericString());
}
}
public void writeField(JsonGenerator jsonGenerator, Object event)
throws IOException
{
writeField(jsonGenerator, event, new ArrayDeque<Object>());
}
private void writeField(JsonGenerator jsonGenerator, Object event, Deque<Object> objectStack)
throws IOException
{
Object value = getValue(event);
if (value != null) {
jsonGenerator.writeFieldName(name);
if (containerType == ContainerType.ITERABLE) {
validateFieldValueType(value, Iterable.class);
writeArray(jsonGenerator, (Iterable<?>) value, objectStack);
}
else if (containerType == ContainerType.MAP) {
validateFieldValueType(value, Map.class);
writeMap(jsonGenerator, (Map<?, ?>) value, objectStack);
}
else if (containerType == ContainerType.MULTIMAP) {
validateFieldValueType(value, Multimap.class);
writeMultimap(jsonGenerator, (Multimap<?, ?>) value, objectStack);
}
else {
writeFieldValue(jsonGenerator, value, objectStack);
}
}
}
private void writeFieldValue(JsonGenerator jsonGenerator, Object value, Deque<Object> objectStack)
throws IOException
{
if (eventDataType != null) {
eventDataType.writeFieldValue(jsonGenerator, value);
}
else {
validateFieldValueType(value, nestedType.getEventClass());
writeObject(jsonGenerator, value, objectStack);
}
}
private void writeArray(JsonGenerator jsonGenerator, Iterable<?> value, Deque<Object> objectStack)
throws IOException
{
jsonGenerator.writeStartArray();
for (Object item : value) {
writeFieldValue(jsonGenerator, item, objectStack);
}
jsonGenerator.writeEndArray();
}
private void writeMap(JsonGenerator jsonGenerator, Map<?, ?> value, Deque<Object> objectStack)
throws IOException
{
jsonGenerator.writeStartObject();
for (Map.Entry<?, ?> entry : value.entrySet()) {
jsonGenerator.writeFieldName((String) entry.getKey());
writeFieldValue(jsonGenerator, entry.getValue(), objectStack);
}
jsonGenerator.writeEndObject();
}
private void writeMultimap(JsonGenerator jsonGenerator, Multimap<?, ?> value, Deque<Object> objectStack)
throws IOException
{
jsonGenerator.writeStartObject();
for (Map.Entry<?, ? extends Collection<?>> entry : value.asMap().entrySet()) {
jsonGenerator.writeFieldName((String) entry.getKey());
writeArray(jsonGenerator, entry.getValue(), objectStack);
}
jsonGenerator.writeEndObject();
}
private void writeObject(JsonGenerator jsonGenerator, Object value, Deque<Object> objectStack)
throws IOException
{
checkForCycles(value, objectStack);
objectStack.push(value);
jsonGenerator.writeStartObject();
for (EventFieldMetadata field : nestedType.getFields()) {
field.writeField(jsonGenerator, value, objectStack);
}
jsonGenerator.writeEndObject();
objectStack.pop();
}
private static void checkForCycles(Object value, Deque<Object> objectStack)
throws InvalidEventException
{
for (Object o : objectStack) {
if (value == o) {
List<Object> path = Lists.reverse(Lists.newArrayList(objectStack));
throw new InvalidEventException("Cycle detected in event data: %s", path);
}
}
}
public void writeFieldV1(JsonGenerator jsonGenerator, Object event)
throws IOException
{
Preconditions.checkState(containerType == null, "%s fields not supported for JSON V1", containerType);
Preconditions.checkState(nestedType == null, "nested types not supported for JSON V1");
Object value = getValue(event);
if (value != null) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", v1Name);
jsonGenerator.writeFieldName("value");
eventDataType.writeFieldValue(jsonGenerator, value);
jsonGenerator.writeEndObject();
}
}
public void writeTimestampV1(JsonGenerator jsonGenerator, Object event)
throws IOException
{
Object value = getValue(event);
if (value != null) {
EventDataType.validateFieldValueType(value, DateTime.class);
jsonGenerator.writeNumberField("timestamp", ((DateTime) value).getMillis());
}
}
}