/******************************************************************************* * 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; import java.util.ArrayList; import java.util.List; import jsr166y.ForkJoinPool; import net.sf.jacclog.api.LogEntryService; import net.sf.jacclog.api.domain.ReadableLogEntry; 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.service.analyzer.internal.task.AnalysisByEntriesTask; import net.sf.jacclog.service.analyzer.internal.task.AnalysisByIntervalTask; import net.sf.jacclog.uasparser.UserAgentStringParser; import org.joda.time.Interval; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogEntryAnalyzer implements net.sf.jacclog.service.analyzer.LogEntryAnalyzer { private static final Logger LOG = LoggerFactory.getLogger(LogEntryAnalyzer.class); protected static final int THREADS = Runtime.getRuntime().availableProcessors(); /** * Casts a <code>long</code> to an <code>int</code> if the value not smaller than {@link Integer.MIN_VALUE} or * greater than {@link Integer.MAX_VALUE}. * * @param longValue * @throws IllegalArgumentException * If the given <code>long</code> is smaller than {@link Integer.MIN_VALUE} or greater than * {@link Integer.MAX_VALUE} * @return An <code>int</code> */ private static int castLongToInt(final long longValue) { if (longValue < Integer.MIN_VALUE || longValue > Integer.MAX_VALUE) { throw new IllegalArgumentException("Cannot cast '" + longValue + "' to int without changing its value."); } return (int) longValue; } private final LogEntryAnalysisResult.Builder builder = new LogEntryAnalysisResult.Builder(); private final UserAgentStringParser parser; private final LogEntryService<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> service; public LogEntryAnalyzer( final LogEntryService<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> service, final UserAgentStringParser parser) { if (service == null) { throw new IllegalArgumentException("Argument 'service' can not be null."); } if (parser == null) { throw new IllegalArgumentException("Argument 'parser' can not be null."); } this.service = service; this.parser = parser; } @Override public LogEntryAnalyzer analyze(final Interval interval) { validateInterval(interval); // Number of log entries to be analyzed final int count = castLongToInt(service.count(interval)); final AnalysisByIntervalTask analyzer = new AnalysisByIntervalTask(service, parser, builder, interval, 0, count); final ForkJoinPool pool = new ForkJoinPool(THREADS); pool.invoke(analyzer); LOG.info("Done. Analyzed: " + count); return this; } @Override public LogEntryAnalyzer analyze( final List<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> entries) { if (entries == null) { throw new IllegalArgumentException("Argument 'entries' can not be null."); } final AnalysisByEntriesTask analyzer = new AnalysisByEntriesTask(entries, parser, builder, 0, entries.size()); final ForkJoinPool pool = new ForkJoinPool(THREADS); pool.invoke(analyzer); LOG.info("Done. Analyzed: " + entries.size()); return this; } @Override public LogEntryAnalyzer analyze( final ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField> entry) { if (entry == null) { throw new IllegalArgumentException("Argument 'entry' can not be null."); } final List<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> entries = new ArrayList<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>>(); entries.add(entry); analyze(entries); return this; } public LogEntryAnalysisResult.Builder getBuilder() { return builder; } public UserAgentStringParser getParser() { return parser; } public LogEntryService<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> getService() { return service; } @Override public LogEntryAnalysisResult toResult() { return builder.build(); } /** * Validates a time interval if it is suitable for an analysis. * * @param interval * Time interval */ private void validateInterval(final Interval interval) { if (interval == null) { throw new IllegalArgumentException("Argument 'interval' can not be null."); } if (interval.getStart().isAfter(interval.getEndMillis())) { throw new IllegalArgumentException("The time interval specify an negative range."); } } }