/*
* Copyright 2012-present Facebook, Inc.
*
* Licensed 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.facebook.buck.event;
import com.facebook.buck.log.views.JsonViews;
import com.facebook.buck.model.BuildId;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import java.util.Objects;
import javax.annotation.Nullable;
/**
* Base class for all build events. Using this makes it easy to add a wildcard listener to the event
* bus.
*/
public abstract class AbstractBuckEvent implements BuckEvent {
private boolean isConfigured;
private long timestamp;
private long nanoTime;
private long threadUserNanoTime;
private long threadId;
@Nullable private BuildId buildId;
private final EventKey eventKey;
protected AbstractBuckEvent(EventKey eventKey) {
this.isConfigured = false;
this.eventKey = Preconditions.checkNotNull(eventKey);
}
/**
* Method to configure an event before posting it to the {@link BuckEventBus}. This method should
* only be invoked once per event, and only by the {@link BuckEventBus} in production code.
*/
@Override
@VisibleForTesting
public void configure(
long timestamp, long nanoTime, long threadUserNanoTime, long threadId, BuildId buildId) {
Preconditions.checkState(!isConfigured, "Events can only be configured once.");
this.timestamp = timestamp;
this.nanoTime = nanoTime;
this.threadUserNanoTime = threadUserNanoTime;
this.threadId = threadId;
this.buildId = buildId;
isConfigured = true;
}
@Override
public boolean isConfigured() {
return isConfigured;
}
@Override
@JsonView(JsonViews.MachineReadableLog.class)
public long getTimestamp() {
Preconditions.checkState(isConfigured, "Event was not configured yet.");
return timestamp;
}
@Override
public long getNanoTime() {
Preconditions.checkState(isConfigured, "Event was not configured yet.");
return nanoTime;
}
@Override
public long getThreadUserNanoTime() {
return threadUserNanoTime;
}
@Override
public String toLogMessage() {
return toString();
}
@Override
public long getThreadId() {
Preconditions.checkState(isConfigured, "Event was not configured yet.");
return threadId;
}
@Override
public BuildId getBuildId() {
Preconditions.checkState(isConfigured, "Event was not configured yet.");
return Preconditions.checkNotNull(buildId);
}
@Override
public final EventKey getEventKey() {
return eventKey;
}
@Override
public final boolean isRelatedTo(BuckEvent event) {
return getEventKey().equals(event.getEventKey());
}
@JsonIgnore
protected abstract String getValueString();
@Override
public String toString() {
return String.format("%s(%s)", getEventName(), getValueString());
}
/**
* The default implementation of equals checks to see if two events are related, are on the same
* thread, and are the same concrete class. Subclasses therefore can simply override isRelatedTo,
* and the equals method will work correctly.
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof AbstractBuckEvent)) {
return false;
}
AbstractBuckEvent that = (AbstractBuckEvent) o;
return isRelatedTo(that) && Objects.equals(getClass(), that.getClass());
}
@Override
public int hashCode() {
return Objects.hash(getClass(), getEventKey());
}
}