/******************************************************************************* * Copyright 2011 André Rouél * * 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 net.sf.jacclog.service.analyzer.internal.task; import java.util.List; import jsr166y.RecursiveAction; import net.sf.jacclog.api.domain.ReadableLogEntry; import net.sf.jacclog.api.domain.http.HttpRequestHeader; import net.sf.jacclog.api.domain.http.ReadableHttpRequestHeaderField; import net.sf.jacclog.api.domain.http.ReadableHttpResponseHeaderField; import net.sf.jacclog.service.analyzer.LogEntryAnalysisResult; import net.sf.jacclog.uasparser.UserAgentStringParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AnalysisByEntriesTask extends RecursiveAction { private static final Logger LOG = LoggerFactory.getLogger(AnalysisByEntriesTask.class); private static final long serialVersionUID = -4821190673644807216L; protected static final int THRESHOLD = 200; /** * Searches in the request headers of the given log entry for an user agent string. * * @param entry * the log entry * @return the user agent string or <code>null</code> */ public static String searchUserAgent( final ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField> entry) { String userAgent = null; for (final ReadableHttpRequestHeaderField header : entry.getRequestHeaders()) { if (header.getType().equals(HttpRequestHeader.USER_AGENT)) { userAgent = header.getValue(); } } return userAgent; } private final int maxResults; private final UserAgentStringParser parser; private final List<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> entries; private final LogEntryAnalysisResult.Builder builder; private final int startPosition; public AnalysisByEntriesTask( final List<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> entries, final UserAgentStringParser parser, final LogEntryAnalysisResult.Builder builder, final int startPosition, final int maxResults) { if (entries == null) { throw new IllegalArgumentException("Argument 'entries' can not be null."); } if (parser == null) { throw new IllegalArgumentException("Argument 'parser' can not be null."); } if (builder == null) { throw new IllegalArgumentException("Argument 'builder' can not be null."); } if (startPosition < 0) { throw new IllegalArgumentException("Argument 'startPosition' can not be smaller than 0."); } if (maxResults < 1) { throw new IllegalArgumentException("Argument 'maxResults' can not be smaller than 1."); } this.entries = entries; this.parser = parser; this.builder = builder; this.startPosition = startPosition; this.maxResults = maxResults; } @Override protected void compute() { if (maxResults < THRESHOLD) { try { final List<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> entries = this.entries .subList(startPosition, startPosition + maxResults); if (!entries.isEmpty()) { String userAgent = null; for (final ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField> entry : entries) { userAgent = searchUserAgent(entry); if (userAgent != null) { builder.appendUserAgentInfo(parser.parse(userAgent)); } } } } catch (final IndexOutOfBoundsException e) { LOG.warn("Analyzing user agent information failed: " + e.getLocalizedMessage()); } } else { final int midpoint = maxResults / 2; final AnalysisByEntriesTask a1 = new AnalysisByEntriesTask(entries, parser, builder, startPosition, midpoint); final AnalysisByEntriesTask a2 = new AnalysisByEntriesTask(entries, parser, builder, startPosition + midpoint, maxResults - midpoint); invokeAll(a1, a2); } } }