package rocks.inspectit.shared.cs.cmr.service.cache; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import rocks.inspectit.shared.all.cmr.model.JmxDefinitionDataIdent; import rocks.inspectit.shared.all.cmr.model.MethodIdent; import rocks.inspectit.shared.all.cmr.model.PlatformIdent; import rocks.inspectit.shared.all.cmr.model.SensorTypeIdent; import rocks.inspectit.shared.all.cmr.service.ICachedDataService; import rocks.inspectit.shared.all.communication.data.cmr.AgentStatusData; import rocks.inspectit.shared.all.communication.data.cmr.ApplicationData; import rocks.inspectit.shared.all.communication.data.cmr.BusinessTransactionData; import rocks.inspectit.shared.all.exception.BusinessException; import rocks.inspectit.shared.all.util.Pair; import rocks.inspectit.shared.cs.cmr.service.IBusinessContextManagementService; import rocks.inspectit.shared.cs.cmr.service.IGlobalDataAccessService; /** * The default implementation of the cached ident objects. Provides a protected-visible method to * analyze and put a list of platform ident objects into the cache. * <p> * The implementing classes should realize the {@link #shouldRefreshIdents()} method to properly * instruct clearing of cache when needed. * * @author Patrice Bouillet * @author Ivan Senic * */ @Component public class CachedDataService implements InitializingBean, ICachedDataService { /** * Logger for the class. Needed to be directly assigned, because this class is used on the UI * with no Spring to enhance it. */ private static final Logger LOG = LoggerFactory.getLogger(CachedDataService.class); /** * Delegated service. */ @Autowired private IGlobalDataAccessService globalDataAccessService; /** * Delegate business context service. */ @Autowired private IBusinessContextManagementService businessContextService; /** * This map is needed to store the mapping between the ID's and the {@link PlatformIdent} * objects. Some views / editors need this information because they can only access the ID. */ private Map<Long, PlatformIdent> platformMap = new ConcurrentHashMap<>(); /** * This map is needed to store the mapping between the ID's and the {@link SensorTypeIdent} * objects. Some views / editors need this information because they can only access the ID. */ private Map<Long, SensorTypeIdent> sensorTypeMap = new ConcurrentHashMap<>(); /** * This map is needed to store the mapping between the ID's and the {@link MethodIdent} objects. * Some views / editors need this information because they can only access the ID. */ private Map<Long, MethodIdent> methodMap = new ConcurrentHashMap<>(); /** * This map is needed to store the mapping between the ID's and the * {@link JmxDefinitionDataIdent} objects. Some views / editors need this information because * they can only access the ID. */ private Map<Long, JmxDefinitionDataIdent> jmxDefinitionDataMap = new ConcurrentHashMap<>(); /** * This map is needed to store the mapping between the ID's and the {@link ApplicationData} * objects. Some views / editors need this information because they can only access the ID. */ private final Map<Integer, ApplicationData> applicationMap = new ConcurrentHashMap<Integer, ApplicationData>(); /** * This map is needed to store the mapping between the ID's and the * {@link BusinessTransactionData} objects. Some views / editors need this information because * they can only access the ID. */ private final Map<Pair<Integer, Integer>, BusinessTransactionData> businessTransactionsMap = new ConcurrentHashMap<Pair<Integer, Integer>, BusinessTransactionData>(); /** * No-args constructor. */ public CachedDataService() { } /** * @param globalDataAccessService * Delegated service. * @param businessContextService * Delegated {@link IBusinessContextManagementService} */ public CachedDataService(IGlobalDataAccessService globalDataAccessService, IBusinessContextManagementService businessContextService) { this.globalDataAccessService = globalDataAccessService; this.businessContextService = businessContextService; } /** * This is a hook method for all subclasses that will be called after the idents have been * refreshed due to the fact that {@link #shouldRefreshIdents()} reports ident should be * refreshed. */ protected void postRefreshIdents() { } /** * Triggers the refresh of the idents. After refresh {@link #postRefreshIdents()} will be * executed. */ public void triggerRefreshIdents() { refreshIdents(); postRefreshIdents(); } /** * Updates the data in the cache for the one agent. This method should be called with care, * since it removes and inserts all the sensor data. * * @param platformIdent * Agento to refresh. */ public void refreshData(PlatformIdent platformIdent) { platformMap.remove(platformIdent.getId()); platformMap.put(platformIdent.getId(), platformIdent); for (MethodIdent methodIdent : platformIdent.getMethodIdents()) { methodMap.remove(methodIdent.getId()); methodMap.put(methodIdent.getId(), methodIdent); } for (SensorTypeIdent sensorTypeIdent : platformIdent.getSensorTypeIdents()) { sensorTypeMap.remove(sensorTypeIdent.getId()); sensorTypeMap.put(sensorTypeIdent.getId(), sensorTypeIdent); } for (JmxDefinitionDataIdent jmxDefinitionDataIdent : platformIdent.getJmxDefinitionDataIdents()) { jmxDefinitionDataMap.remove(jmxDefinitionDataIdent.getId()); jmxDefinitionDataMap.put(jmxDefinitionDataIdent.getId(), jmxDefinitionDataIdent); } } /** * {@inheritDoc} */ @Override public PlatformIdent getPlatformIdentForId(long platformId) { Long id = Long.valueOf(platformId); // load only if the id is not 0 if ((0 != id.longValue()) && !platformMap.containsKey(id)) { refreshIdents(); } return platformMap.get(id); } /** * {@inheritDoc} */ @Override public SensorTypeIdent getSensorTypeIdentForId(long sensorTypeId) { Long id = Long.valueOf(sensorTypeId); // load only if the id is not 0 if ((0 != id.longValue()) && !sensorTypeMap.containsKey(id)) { refreshIdents(); } return sensorTypeMap.get(id); } /** * {@inheritDoc} */ @Override public MethodIdent getMethodIdentForId(long methodId) { Long id = Long.valueOf(methodId); // load only if the id is not 0 if ((0 != id.longValue()) && !methodMap.containsKey(id)) { refreshIdents(); } return methodMap.get(id); } /** * {@inheritDoc} */ @Override public JmxDefinitionDataIdent getJmxDefinitionDataIdentForId(long jmxDefinitionDataId) { Long id = Long.valueOf(jmxDefinitionDataId); // load only if the id is not 0 if ((0 != id.longValue()) && !jmxDefinitionDataMap.containsKey(id)) { refreshIdents(); } return jmxDefinitionDataMap.get(id); } /** * {@inheritDoc} */ @Override public ApplicationData getApplicationForId(int id) { if (!applicationMap.containsKey(id)) { refreshBusinessContext(); } return applicationMap.get(id); } /** * {@inheritDoc} */ @Override public BusinessTransactionData getBusinessTransactionForId(int appId, int businessTxId) { Pair<Integer, Integer> keyPair = new Pair<Integer, Integer>(appId, businessTxId); if (!businessTransactionsMap.containsKey(keyPair)) { refreshBusinessContext(); } BusinessTransactionData businessTxData = businessTransactionsMap.get(keyPair); return businessTxData; } /** * Internal refresh of the idents. Currently everything is loaded again. */ protected void refreshIdents() { Map<PlatformIdent, AgentStatusData> agentMap = globalDataAccessService.getAgentsOverview(); platformMap.clear(); methodMap.clear(); sensorTypeMap.clear(); jmxDefinitionDataMap.clear(); for (PlatformIdent overview : agentMap.keySet()) { PlatformIdent platformIdent; try { platformIdent = globalDataAccessService.getCompleteAgent(overview.getId()); } catch (BusinessException e) { LOG.warn("Exception occurred trying to refresh sensor information for the agent " + overview.getAgentName() + ".", e); continue; } platformMap.put(platformIdent.getId(), platformIdent); for (MethodIdent methodIdent : platformIdent.getMethodIdents()) { methodMap.put(methodIdent.getId(), methodIdent); } for (SensorTypeIdent sensorTypeIdent : platformIdent.getSensorTypeIdents()) { sensorTypeMap.put(sensorTypeIdent.getId(), sensorTypeIdent); } for (JmxDefinitionDataIdent jmxDefinitionDataIdent : platformIdent.getJmxDefinitionDataIdents()) { jmxDefinitionDataMap.put(jmxDefinitionDataIdent.getId(), jmxDefinitionDataIdent); } } } /** * Reloads the business context data. */ private void refreshBusinessContext() { applicationMap.clear(); businessTransactionsMap.clear(); for (BusinessTransactionData businessTx : businessContextService.getBusinessTransactions()) { businessTransactionsMap.put(new Pair<Integer, Integer>(businessTx.getApplication().getId(), businessTx.getId()), businessTx); } for (ApplicationData application : businessContextService.getApplications()) { applicationMap.put(application.getId(), application); } } /** * {@inheritDoc} */ @Override public void afterPropertiesSet() throws Exception { refreshIdents(); refreshBusinessContext(); } }