/*
* Copyright 2015 NAVER Corp.
*
* 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.navercorp.pinpoint.web.service;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
import com.navercorp.pinpoint.common.server.util.AgentEventTypeCategory;
import com.navercorp.pinpoint.web.vo.DurationalAgentEvent;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.navercorp.pinpoint.common.server.bo.AgentEventBo;
import com.navercorp.pinpoint.common.server.util.AgentEventMessageDeserializer;
import com.navercorp.pinpoint.common.server.util.AgentEventType;
import com.navercorp.pinpoint.web.dao.AgentEventDao;
import com.navercorp.pinpoint.web.vo.AgentEvent;
import com.navercorp.pinpoint.web.vo.Range;
/**
* @author HyunGil Jeong
*/
@Service
public class AgentEventServiceImpl implements AgentEventService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private AgentEventDao agentEventDao;
@Autowired
private AgentEventMessageDeserializer agentEventMessageDeserializer;
@Override
public List<AgentEvent> getAgentEvents(String agentId, Range range, int... excludeEventTypeCodes) {
if (agentId == null) {
throw new NullPointerException("agentId must not be null");
}
final boolean includeEventMessage = false;
Set<AgentEventType> excludeEventTypes = EnumSet.noneOf(AgentEventType.class);
for (int excludeEventTypeCode : excludeEventTypeCodes) {
AgentEventType excludeEventType = AgentEventType.getTypeByCode(excludeEventTypeCode);
if (excludeEventType != null) {
excludeEventTypes.add(excludeEventType);
}
}
List<AgentEventBo> agentEventBos = this.agentEventDao.getAgentEvents(agentId, range, excludeEventTypes);
List<AgentEvent> agentEvents = createAgentEvents(agentEventBos, includeEventMessage);
Collections.sort(agentEvents, AgentEvent.EVENT_TIMESTAMP_ASC_COMPARATOR);
return agentEvents;
}
@Override
public AgentEvent getAgentEvent(String agentId, long eventTimestamp, int eventTypeCode) {
if (agentId == null) {
throw new NullPointerException("agentId must not be null");
}
if (eventTimestamp < 0) {
throw new IllegalArgumentException("eventTimeTimestamp must not be less than 0");
}
final AgentEventType eventType = AgentEventType.getTypeByCode(eventTypeCode);
if (eventType == null) {
throw new IllegalArgumentException("invalid eventTypeCode [" + eventTypeCode + "]");
}
final boolean includeEventMessage = true;
AgentEventBo agentEventBo = this.agentEventDao.getAgentEvent(agentId, eventTimestamp, eventType);
if (agentEventBo != null) {
return createAgentEvent(agentEventBo, includeEventMessage);
}
return null;
}
private List<AgentEvent> createAgentEvents(List<AgentEventBo> agentEventBos, boolean includeEventMessage) {
if (CollectionUtils.isEmpty(agentEventBos)) {
return Collections.emptyList();
}
List<AgentEvent> agentEvents = new ArrayList<>(agentEventBos.size());
PriorityQueue<DurationalAgentEvent> durationalAgentEvents = new PriorityQueue<>(agentEventBos.size(), AgentEvent.EVENT_TIMESTAMP_ASC_COMPARATOR);
for (AgentEventBo agentEventBo : agentEventBos) {
if (agentEventBo.getEventType().isCategorizedAs(AgentEventTypeCategory.DURATIONAL)) {
durationalAgentEvents.add(createDurationalAgentEvent(agentEventBo, includeEventMessage));
} else {
agentEvents.add(createAgentEvent(agentEventBo, includeEventMessage));
}
}
long durationStartTimestamp = DurationalAgentEvent.UNKNOWN_TIMESTAMP;
while (!durationalAgentEvents.isEmpty()) {
DurationalAgentEvent currentEvent = durationalAgentEvents.remove();
if (durationStartTimestamp == DurationalAgentEvent.UNKNOWN_TIMESTAMP) {
durationStartTimestamp = currentEvent.getEventTimestamp();
}
currentEvent.setDurationStartTimestamp(durationStartTimestamp);
DurationalAgentEvent nextEvent = durationalAgentEvents.peek();
if (nextEvent != null) {
long nextEventTimestamp = nextEvent.getEventTimestamp();
currentEvent.setDurationEndTimestamp(nextEventTimestamp);
durationStartTimestamp = nextEventTimestamp;
}
agentEvents.add(currentEvent);
}
return agentEvents;
}
private AgentEvent createAgentEvent(AgentEventBo agentEventBo, boolean includeEventMessage) {
AgentEvent agentEvent = new AgentEvent(agentEventBo);
if (includeEventMessage) {
agentEvent.setEventMessage(deserializeEventMessage(agentEventBo));
}
return agentEvent;
}
@Deprecated
private DurationalAgentEvent createDurationalAgentEvent(AgentEventBo agentEventBo, boolean includeEventMessage) {
DurationalAgentEvent durationalAgentEvent = new DurationalAgentEvent(agentEventBo);
if (includeEventMessage) {
durationalAgentEvent.setEventMessage(deserializeEventMessage(agentEventBo));
}
return durationalAgentEvent;
}
private Object deserializeEventMessage(AgentEventBo agentEventBo) {
try {
return this.agentEventMessageDeserializer.deserialize(agentEventBo.getEventType(), agentEventBo.getEventBody());
} catch (UnsupportedEncodingException e) {
logger.warn("error deserializing event message", e);
return null;
}
}
}