/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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 org.apache.cxf.metrics.interceptors; import java.io.Closeable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.cxf.Bus; import org.apache.cxf.configuration.ConfiguredBeanLocator; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageUtils; import org.apache.cxf.metrics.ExchangeMetrics; import org.apache.cxf.metrics.MetricsContext; import org.apache.cxf.metrics.MetricsProvider; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.service.model.BindingOperationInfo; public abstract class AbstractMetricsInterceptor extends AbstractPhaseInterceptor<Message> { private static final String REST_METRICS_MAP = AbstractMetricsInterceptor.class.getName() + ".METRICS_MAP"; MetricsProvider providers[]; public AbstractMetricsInterceptor(String phase, MetricsProvider p[]) { super(phase); providers = p; } protected Collection<? extends MetricsProvider> getMetricProviders(Bus bus) { if (providers != null) { return Arrays.asList(providers); } ConfiguredBeanLocator b = bus.getExtension(ConfiguredBeanLocator.class); if (b == null) { return Collections.emptyList(); } return b.getBeansOfType(MetricsProvider.class); } protected ExchangeMetrics getExchangeMetrics(Message m, boolean create) { ExchangeMetrics ctx = m.getExchange().get(ExchangeMetrics.class); if (ctx == null && create) { ctx = new ExchangeMetrics(m.getExchange()); m.getExchange().put(ExchangeMetrics.class, ctx); addEndpointMetrics(ctx, m); } return ctx; } private void addEndpointMetrics(ExchangeMetrics ctx, Message m) { Endpoint ep = m.getExchange().getEndpoint(); Object o = ep.get(MetricsContext.class.getName()); if (o == null) { synchronized (ep) { o = createEndpointMetrics(m); } } if (o instanceof List) { List<MetricsContext> list = CastUtils.cast((List<?>)o); for (MetricsContext c : list) { ctx.addContext(c); } } else if (o instanceof MetricsContext) { ctx.addContext((MetricsContext)o); } } private Object createEndpointMetrics(Message m) { final Endpoint ep = m.getExchange().getEndpoint(); Object o = ep.get(MetricsContext.class.getName()); if (o == null) { List<MetricsContext> contexts = new ArrayList<>(); for (MetricsProvider p : getMetricProviders(m.getExchange().getBus())) { MetricsContext c = p.createEndpointContext(ep, MessageUtils.isRequestor(m), (String)m.getContextualProperty(MetricsProvider.CLIENT_ID)); if (c != null) { contexts.add(c); } if (c instanceof Closeable) { ep.addCleanupHook((Closeable)c); } } if (contexts.size() == 1) { o = contexts.get(0); } else { o = contexts; } ep.put(MetricsContext.class.getName(), o); } return o; } private Map<String, Object> getRestMetricsMap(Endpoint e) { synchronized (e) { Object mmo = e.get(REST_METRICS_MAP); if (mmo == null) { e.put(REST_METRICS_MAP, new ConcurrentHashMap<String, Object>()); mmo = e.get(REST_METRICS_MAP); } return CastUtils.cast((Map<?, ?>)mmo); } } protected void addOperationMetrics(ExchangeMetrics ctx, Message m, BindingOperationInfo boi) { Object metrics = null; if (boi == null) { //likely a REST service, let's see if we have a resource name Object nameProperty = m.getExchange().get("org.apache.cxf.resource.operation.name"); if (nameProperty != null) { Map<String, Object> restMap = getRestMetricsMap(m.getExchange().getEndpoint()); metrics = restMap.get(nameProperty.toString()); if (metrics == null) { metrics = createMetricsContextForRestResource(m, nameProperty.toString()); } } } else { if (boi.isUnwrapped()) { boi = boi.getWrappedOperation(); } metrics = boi.getProperty(MetricsContext.class.getName()); if (metrics == null) { synchronized (boi) { metrics = createMetricsContextForOperation(m, boi); } } } if (metrics instanceof List) { List<MetricsContext> list = CastUtils.cast((List<?>)metrics); for (MetricsContext c : list) { ctx.addContext(c); } } else if (metrics instanceof MetricsContext) { ctx.addContext((MetricsContext)metrics); } } private synchronized Object createMetricsContextForRestResource(Message message, String resource) { Map<String, Object> restMap = getRestMetricsMap(message.getExchange().getEndpoint()); Object o = restMap.get(resource); if (o != null) { return o; } List<MetricsContext> contexts = new ArrayList<>(); for (MetricsProvider p : getMetricProviders(message.getExchange().getBus())) { MetricsContext c = p.createResourceContext(message.getExchange().getEndpoint(), resource, MessageUtils.isRequestor(message), (String)message.getContextualProperty(MetricsProvider.CLIENT_ID)); if (c != null) { contexts.add(c); } if (c instanceof Closeable) { message.getExchange().getEndpoint().addCleanupHook((Closeable)c); } } if (contexts.size() == 1) { o = contexts.get(0); } else { o = contexts; } restMap.put(resource, o); return o; } private Object createMetricsContextForOperation(Message message, BindingOperationInfo boi) { Object o = boi.getProperty(MetricsContext.class.getName()); if (o == null) { List<MetricsContext> contexts = new ArrayList<>(); for (MetricsProvider p : getMetricProviders(message.getExchange().getBus())) { MetricsContext c = p.createOperationContext(message.getExchange().getEndpoint(), boi, MessageUtils.isRequestor(message), (String)message.getContextualProperty(MetricsProvider.CLIENT_ID)); if (c != null) { contexts.add(c); } if (c instanceof Closeable) { message.getExchange().getEndpoint().addCleanupHook((Closeable)c); } } if (contexts.size() == 1) { o = contexts.get(0); } else { o = contexts; } boi.setProperty(MetricsContext.class.getName(), o); } return o; } public void stop(Message m) { ExchangeMetrics ctx = getExchangeMetrics(m, false); if (ctx != null) { ctx.stop(); } } }