/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Cloudera, Inc. licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudera.flume.core;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;
import org.apache.commons.lang.StringEscapeUtils;
import com.cloudera.flume.conf.FlumeConfiguration;
import com.cloudera.util.Clock;
import com.cloudera.util.NetUtils;
import com.google.common.base.Preconditions;
/**
* A simple in memory implementation of an event.
*
* I'm limiting a message to be at most 32k
*/
public class EventImpl extends EventBaseImpl {
byte[] body;
long timestamp;
Priority pri;
long nanos;
String host;
final static long MAX_BODY_SIZE = FlumeConfiguration.get().getEventMaxSizeBytes();
/**
* Reflection based tools (like avro) require a null constructor
*/
public EventImpl() {
this(new byte[0], 0, Priority.INFO, 0, "");
}
/**
* Copy constructor for converting events into EventImpl (required for
* reflection/avro)
*/
public EventImpl(Event e) {
this(e.getBody(), e.getTimestamp(), e.getPriority(), e.getNanos(), e
.getHost(), new HashMap<String, byte[]>(e.getAttrs()));
}
/**
* Constructs a new event wrapping (not copying!) the provided byte array
*/
public EventImpl(byte[] s) {
this(s, Clock.unixTime(), Priority.INFO, Clock.nanos(), NetUtils
.localhost());
}
/**
* Constructs a new event wrapping (not copying!) the provided byte array
*/
public EventImpl(byte[] s, Priority pri) {
this(s, Clock.unixTime(), pri, Clock.nanos(), NetUtils.localhost());
}
/**
* Constructs a new event wrapping (not copying!) the provided byte array
*/
public EventImpl(byte[] s, long timestamp, Priority pri, long nanoTime,
String host) {
this(s, timestamp, pri, nanoTime, host, new HashMap<String, byte[]>());
}
/**
* Constructs a new event wrapping (not copying!) the provided byte array
*/
public EventImpl(byte[] s, long timestamp, Priority pri, long nanoTime,
String host, Map<String, byte[]> fields) {
super(fields);
Preconditions.checkNotNull(s);
Preconditions.checkArgument(s.length <= MAX_BODY_SIZE);
// this string construction took ~5% of exec time!
// , "byte length is " + s.length + " which is not < " + MAX_BODY_SIZE);
Preconditions.checkNotNull(pri);
this.body = s;
this.timestamp = timestamp;
this.pri = pri;
this.nanos = nanoTime;
this.host = host;
}
/**
* Returns reference to mutable body of event
*/
public byte[] getBody() {
return body;
}
public Priority getPriority() {
return pri;
}
protected void setPriority(Priority p) {
this.pri = p;
}
/**
* Returns unix time stamp in millis
*/
public long getTimestamp() {
return timestamp;
}
/**
* Set unix time stamp in millis
*/
protected void setTimestamp(long stamp) {
this.timestamp = stamp;
}
public String toString() {
String mbody = StringEscapeUtils.escapeJava(new String(getBody()));
StringBuilder attrs = new StringBuilder();
SortedMap<String, byte[]> sorted = new TreeMap<String, byte[]>(this.fields);
for (Entry<String, byte[]> e : sorted.entrySet()) {
attrs.append("{ " + e.getKey() + " : ");
String o = Attributes.toString(this, e.getKey());
attrs.append(o + " } ");
}
return getHost() + " [" + getPriority().toString() + " "
+ new Date(getTimestamp()) + "] " + attrs.toString() + mbody;
}
@Override
public long getNanos() {
return nanos;
}
@Override
public String getHost() {
return host;
}
/**
* This takes an event and a list of attribute names. It returns a new event
* that has the same core event values but *only * the attributes specified by
* the list.
*/
public static Event select(Event e, String... attrs) {
Event e2 = new EventImpl(e.getBody(), e.getTimestamp(), e.getPriority(), e
.getNanos(), e.getHost());
for (String a : attrs) {
byte[] data = e.get(a);
if (data == null) {
continue;
}
e2.set(a, data);
}
return e2;
}
/**
* This takes an event and a list of attribute names. It returns a new event
* that has the same core event values and all of the attribute/values
* *except* for those attributes sepcified by the list.
*/
public static Event unselect(Event e, String... attrs) {
Event e2 = new EventImpl(e.getBody(), e.getTimestamp(), e.getPriority(), e
.getNanos(), e.getHost());
List<String> as = Arrays.asList(attrs);
for (Entry<String, byte[]> ent : e.getAttrs().entrySet()) {
String a = ent.getKey();
if (as.contains(a)) {
continue; // don't add it if it is in the unselect list.
}
byte[] data = e.get(a);
e2.set(a, data);
}
return e2;
}
}