/* * Copyright 2014 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.applicationmap; import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.web.applicationmap.histogram.*; import com.navercorp.pinpoint.web.applicationmap.rawdata.*; import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModelList; import com.navercorp.pinpoint.web.view.LinkSerializer; import com.navercorp.pinpoint.web.view.ResponseTimeViewModel; import com.navercorp.pinpoint.web.vo.*; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; /** * A class that describes relationship between apps in application map * * @author netspider * @author emeroad */ @JsonSerialize(using = LinkSerializer.class) public class Link { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public static final String LINK_DELIMITER = "~"; // specifies who created the link. // indicates whether it was automatically created by the source, or if it was manually created by the target. private final CreateType createType; private final Node fromNode; private final Node toNode; private final Range range; private final LinkStateResolver linkStateResolver = LinkStateResolver.DEFAULT_LINK_STATE_RESOLVER; private final LinkCallDataMap sourceLinkCallDataMap = new LinkCallDataMap(); private final LinkCallDataMap targetLinkCallDataMap = new LinkCallDataMap(); private Histogram linkHistogram; public Link(CreateType createType, Node fromNode, Node toNode, Range range) { if (createType == null) { throw new NullPointerException("createType must not be null"); } if (fromNode == null) { throw new NullPointerException("fromNode must not be null"); } if (toNode == null) { throw new NullPointerException("toNode must not be null"); } if (range == null) { throw new NullPointerException("range must not be null"); } this.createType = createType; this.fromNode = fromNode; this.toNode = toNode; this.range = range; } public Application getFilterApplication() { // User link: need to look at WAS, not from // Since User is a virtual link, we cannot filter by User if (fromNode.getServiceType() == ServiceType.USER) { return toNode.getApplication(); } // same goes for virtual queue nodes if (!fromNode.getServiceType().isWas() && fromNode.getServiceType().isQueue()) { return toNode.getApplication(); } return fromNode.getApplication(); } public LinkKey getLinkKey() { return new LinkKey(fromNode.getApplication(), toNode.getApplication()); } public Node getFrom() { return fromNode; } public Node getTo() { return toNode; } public Range getRange() { return range; } public String getLinkName() { return fromNode.getNodeName() + LINK_DELIMITER + toNode.getNodeName(); } public LinkCallDataMap getSourceLinkCallDataMap() { return sourceLinkCallDataMap; } public LinkCallDataMap getTargetLinkCallDataMap() { return targetLinkCallDataMap; } public CreateType getCreateType() { return createType; } public AgentHistogramList getTargetList() { return sourceLinkCallDataMap.getTargetList(); } public Histogram getHistogram() { if (linkHistogram == null) { linkHistogram = createHistogram0(); } return linkHistogram; } private Histogram createHistogram0() { // need serviceType of target (callee) // ie. Tomcat -> Arcus: we need arcus type final LinkCallDataMap findMap = getLinkCallDataMap(); AgentHistogramList targetList = findMap.getTargetList(); return targetList.mergeHistogram(toNode.getServiceType()); } private LinkCallDataMap getLinkCallDataMap() { switch (createType) { case Source: return sourceLinkCallDataMap; case Target: return targetLinkCallDataMap; default: throw new IllegalArgumentException("invalid CreateType:" + createType); } } public List<ResponseTimeViewModel> getLinkApplicationTimeSeriesHistogram() { if (createType == CreateType.Source) { return getSourceApplicationTimeSeriesHistogram(); } else { return getTargetApplicationTimeSeriesHistogram(); } } public Histogram getTargetHistogram() { // need serviceType of target (callee) // ie. Tomcat -> Arcus: we need Arcus type AgentHistogramList targetList = targetLinkCallDataMap.getTargetList(); return targetList.mergeHistogram(toNode.getServiceType()); } @JsonIgnore public AgentHistogramList getSourceList() { return sourceLinkCallDataMap.getSourceList(); } public void addSource(LinkCallDataMap sourceLinkCallDataMap) { this.sourceLinkCallDataMap.addLinkDataMap(sourceLinkCallDataMap); } public void addTarget(LinkCallDataMap targetLinkCallDataMap) { this.targetLinkCallDataMap.addLinkDataMap(targetLinkCallDataMap); } public List<ResponseTimeViewModel> getSourceApplicationTimeSeriesHistogram() { ApplicationTimeHistogram histogramData = getSourceApplicationTimeSeriesHistogramData(); return histogramData.createViewModel(); } private ApplicationTimeHistogram getSourceApplicationTimeSeriesHistogramData() { // we need Target (to)'s time since time in link is RPC-based ApplicationTimeHistogramBuilder builder = new ApplicationTimeHistogramBuilder(toNode.getApplication(), range); return builder.build(sourceLinkCallDataMap.getLinkDataList()); } public ApplicationTimeHistogram getTargetApplicationTimeSeriesHistogramData() { // we need Target (to)'s time since time in link is RPC-based ApplicationTimeHistogramBuilder builder = new ApplicationTimeHistogramBuilder(toNode.getApplication(), range); return builder.build(targetLinkCallDataMap.getLinkDataList()); } public AgentResponseTimeViewModelList getSourceAgentTimeSeriesHistogram() { // we need Target (to)'s time since time in link is RPC-based AgentTimeHistogramBuilder builder = new AgentTimeHistogramBuilder(toNode.getApplication(), range); AgentTimeHistogram applicationTimeSeriesHistogram = builder.buildSource(sourceLinkCallDataMap); AgentResponseTimeViewModelList agentResponseTimeViewModelList = new AgentResponseTimeViewModelList(applicationTimeSeriesHistogram.createViewModel()); return agentResponseTimeViewModelList; } public AgentTimeHistogram getTargetAgentTimeHistogram() { AgentTimeHistogramBuilder builder = new AgentTimeHistogramBuilder(toNode.getApplication(), range); AgentTimeHistogram agentTimeHistogram = builder.buildSource(targetLinkCallDataMap); return agentTimeHistogram; } public Collection<Application> getSourceLinkTargetAgentList() { Set<Application> agentList = new HashSet<>(); Collection<LinkCallData> linkDataList = sourceLinkCallDataMap.getLinkDataList(); for (LinkCallData linkCallData : linkDataList) { agentList.add(new Application(linkCallData.getTarget(), linkCallData.getTargetServiceType())); } return agentList; } public List<ResponseTimeViewModel> getTargetApplicationTimeSeriesHistogram() { ApplicationTimeHistogram targetApplicationTimeHistogramData = getTargetApplicationTimeSeriesHistogramData(); return targetApplicationTimeHistogramData.createViewModel(); } public String getLinkState() { return linkStateResolver.resolve(this); } public Boolean getLinkAlert() { return linkStateResolver.isAlert(this); } public boolean isWasToWasLink() { return this.fromNode.getApplication().getServiceType().isWas() && this.toNode.getApplication().getServiceType().isWas(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Link link = (Link) o; if (!fromNode.equals(link.fromNode)) return false; if (!toNode.equals(link.toNode)) return false; return true; } @Override public int hashCode() { int result = fromNode.hashCode(); result = 31 * result + toNode.hashCode(); return result; } @Override public String toString() { return "Link{" + "from=" + fromNode + " -> to=" + toNode + '}'; } }