package org.glassfish.jersey.server.internal.monitoring;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceMethod;
import org.glassfish.jersey.server.monitoring.ExecutionStatistics;
import org.glassfish.jersey.server.monitoring.ResourceMethodStatistics;
import org.glassfish.jersey.server.monitoring.ResourceStatistics;
final class ResourceStatisticsImpl implements ResourceStatistics {
static class Builder {
private final ConcurrentMap<ResourceMethodStatisticsImpl.Builder, Boolean> methodsBuilders = new ConcurrentHashMap<>();
private final ResourceMethodStatisticsImpl.Factory methodFactory;
private final AtomicReference<ExecutionStatisticsImpl.Builder> resourceExecutionStatisticsBuilder = new
AtomicReference<>();
private final AtomicReference<ExecutionStatisticsImpl.Builder> requestExecutionStatisticsBuilder = new
AtomicReference<>();
private volatile ResourceStatisticsImpl cached;
Builder(final Resource resource, final ResourceMethodStatisticsImpl.Factory methodFactory) {
this(methodFactory);
for (final ResourceMethod method : resource.getResourceMethods()) {
getOrCreate(method);
}
}
Builder(final ResourceMethodStatisticsImpl.Factory methodFactory) {
this.methodFactory = methodFactory;
}
ResourceStatisticsImpl build() {
ResourceStatisticsImpl cachedReference = cached;
if (cachedReference != null) {
return cachedReference;
}
final Map<ResourceMethod, ResourceMethodStatistics> resourceMethods = new HashMap<>();
for (final ResourceMethodStatisticsImpl.Builder builder : methodsBuilders.keySet()) {
final ResourceMethodStatisticsImpl stats = builder.build();
resourceMethods.put(stats.getResourceMethod(), stats);
}
final ExecutionStatistics resourceStats = resourceExecutionStatisticsBuilder.get() == null
? ExecutionStatisticsImpl.EMPTY : resourceExecutionStatisticsBuilder.get().build();
final ExecutionStatistics requestStats = requestExecutionStatisticsBuilder.get() == null
? ExecutionStatisticsImpl.EMPTY : requestExecutionStatisticsBuilder.get().build();
final ResourceStatisticsImpl stats = new ResourceStatisticsImpl(resourceMethods,
resourceStats, requestStats);
if (MonitoringUtils.isCacheable(requestStats)) {
cached = stats;
}
return stats;
}
void addExecution(final ResourceMethod resourceMethod, final long methodStartTime, final long methodDuration,
final long requestStartTime, final long requestDuration) {
cached = null;
if (resourceExecutionStatisticsBuilder.get() == null) {
resourceExecutionStatisticsBuilder.compareAndSet(null, new ExecutionStatisticsImpl.Builder());
}
resourceExecutionStatisticsBuilder.get().addExecution(methodStartTime, methodDuration);
if (requestExecutionStatisticsBuilder.get() == null) {
requestExecutionStatisticsBuilder.compareAndSet(null, new ExecutionStatisticsImpl.Builder());
}
requestExecutionStatisticsBuilder.get().addExecution(requestStartTime, requestDuration);
addMethod(resourceMethod);
}
void addMethod(final ResourceMethod resourceMethod) {
cached = null;
getOrCreate(resourceMethod);
}
private ResourceMethodStatisticsImpl.Builder getOrCreate(final ResourceMethod resourceMethod) {
final ResourceMethodStatisticsImpl.Builder methodStats = methodFactory.getOrCreate(resourceMethod);
methodsBuilders.putIfAbsent(methodStats, Boolean.TRUE);
return methodStats;
}
}
private final Map<ResourceMethod, ResourceMethodStatistics> resourceMethods;
private final ExecutionStatistics resourceExecutionStatistics;
private final ExecutionStatistics requestExecutionStatistics;
private ResourceStatisticsImpl(final Map<ResourceMethod, ResourceMethodStatistics> resourceMethods,
final ExecutionStatistics resourceExecutionStatistics,
final ExecutionStatistics requestExecutionStatistics) {
this.resourceMethods = Collections.unmodifiableMap(resourceMethods);
this.resourceExecutionStatistics = resourceExecutionStatistics;
this.requestExecutionStatistics = requestExecutionStatistics;
}
@Override
public ExecutionStatistics getResourceMethodExecutionStatistics() {
return resourceExecutionStatistics;
}
@Override
public ExecutionStatistics getRequestExecutionStatistics() {
return requestExecutionStatistics;
}
@Override
public Map<ResourceMethod, ResourceMethodStatistics> getResourceMethodStatistics() {
return resourceMethods;
}
@Override
public ResourceStatistics snapshot() {
return this;
}
}