package net.sf.jacclog.api.domain;
import java.net.HttpCookie;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import net.sf.jacclog.api.domain.http.HttpConnectionStatus;
import net.sf.jacclog.api.domain.http.HttpRequestHeaderField;
import net.sf.jacclog.api.domain.http.HttpRequestMethod;
import net.sf.jacclog.api.domain.http.HttpResponseHeaderField;
import net.sf.jacclog.api.domain.http.HttpStatus;
import net.sf.jacclog.api.domain.http.ReadableHttpRequestHeaderField;
import net.sf.jacclog.api.domain.http.ReadableHttpResponseHeaderField;
/**
* Log entry builder creates complex immutable instances of <code>LogEntry</code>.
*
* @see net.sf.jacclog.api.domain.LogEntry
*
* @author André Rouél
*/
public class LogEntryBuilder implements
ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField> {
/**
* Bytes received, including request and headers
*/
private Long bytesReceived = 0l;
/**
* Bytes sent, including headers
*/
private Long bytesSent = 0l;
/**
* Connection status when response was completed.
*/
private HttpConnectionStatus connectionStatus = HttpConnectionStatus.UNKNOWN;
/**
* The contents of cookies in the request sent to the server.
*/
private final Set<HttpCookie> cookies = new HashSet<HttpCookie>();
/**
* Filename
*/
private String filename = "";
/**
* Status for the last request
*/
private HttpStatus lastStatusCode = HttpStatus.UNKNOWN;
/**
* Local IP address
*/
private String localIpAddress = "";
/**
* The process ID of the child that serviced the request.
*/
private Integer processId = 0;
/**
* The query string (prepended with a <code>?</code> if a query string exists, otherwise an empty string)
*/
private String queryString = "";
/**
* The client IP address (like 93.71.122.14) or the corresponding hostname (like jacclog.sf.net) of the remote user
* requesting the page. For performance reasons, many web servers are configured not to do hostname lookups on the
* remote host. This means that all you end up with in the log file is a bunch of IP addresses.
*/
private String remoteHost = "";
/**
* The client IP address of the request
*/
private String remoteIpAddress = "";
/**
* Remote logname (from identd, if supplied). This will return a dash unless IdentityCheck is set On.
*/
private String remoteLogname = "";
/**
* Remote user (from auth; may be bogus if return status (%s) is 401)
*/
private String remoteUser = "";
/**
* The contents of the header line(s) in the request sent to the server.
*/
private final Set<ReadableHttpRequestHeaderField> requestHeaders = new HashSet<ReadableHttpRequestHeaderField>();
/**
* The time taken to serve the request in microseconds.
*/
private Long requestInMillis = 0l;
/**
* The request method.
*/
private HttpRequestMethod requestMethod = HttpRequestMethod.UNKNOWN;
/**
* The request protocol.
*/
private String requestProtocol = "";
/**
* Time the request was received.
*/
private Date requestTime = new Date(0);
/**
* The contents of Foobar: header line(s) in the reply.
*/
private final Set<ReadableHttpResponseHeaderField> responseHeaders = new HashSet<ReadableHttpResponseHeaderField>();
/**
* Size of response in bytes, excluding HTTP headers.<br>
* In CLF format the value '-' will be interpreted as 0 (when no bytes are sent).
*/
private Long responseInBytes = 0l;
/**
* The server name according to the UseCanonicalName setting.
*/
private String serverName = "";
/**
* The canonical port of the server serving the request.
*/
private Integer serverPort = 0;
/**
* Status. For requests that got internally redirected, this is the status of the *original* request --- %...>s for
* the last.
*/
private HttpStatus statusCode = HttpStatus.UNKNOWN;
/**
* The URL path requested, not including any query string.<br>
* <br>
* Placeholder: <code>%U</code>
*/
private String urlPath = "";
/**
* Appends a cookie to the set of cookies.
*
* @param cookie
* a HTTP cookie
* @return itself, for chaining
*/
public LogEntryBuilder appendCookies(final HttpCookie cookie) {
if (cookie == null) {
throw new IllegalArgumentException("Argument 'cookie' can not be null.");
}
this.cookies.add(cookie);
return this;
}
/**
* Appends a HTTP request header to the set of request headers.
*
* @param requestHeader
* a HTTP request header
* @return itself, for chaining
*/
public LogEntryBuilder appendRequestHeaders(final HttpRequestHeaderField requestHeader) {
if (requestHeader == null) {
throw new IllegalArgumentException("Argument 'requestHeader' can not be null.");
}
this.requestHeaders.add(requestHeader);
return this;
}
/**
* Appends a HTTP response header to the set of response headers.
*
* @param responseHeader
* a HTTP response header
* @return itself, for chaining
*/
public LogEntryBuilder appendResponseHeaders(final HttpResponseHeaderField responseHeader) {
if (responseHeader == null) {
throw new IllegalArgumentException("Argument 'responseHeader' can not be null.");
}
this.responseHeaders.add(responseHeader);
return this;
}
/**
* Constructs an immutable <code>LogEntry</code>.
*
* @throws IllegalArgumentException
* if the construction arguments for <code>LogEntry</code> invalid
* @return a new log entry
*/
public LogEntry build() {
return new LogEntry(bytesReceived, bytesSent, connectionStatus, cookies, filename, lastStatusCode,
localIpAddress, processId, queryString, remoteHost, remoteIpAddress, remoteLogname, remoteUser,
requestHeaders, requestInMillis, requestMethod, requestProtocol, requestTime, responseHeaders,
responseInBytes, serverName, serverPort, statusCode, urlPath);
}
/**
* Sets the received bytes including the request and headers. If no received bytes were logged, the given argument
* should be zero.
*
* @param bytesReceived
* the bytes received or <code>0</code>
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @throws IllegalArgumentException
* if the given argument is smaller than <code>0</code>
* @return itself, for chaining
*/
public LogEntryBuilder bytesReceived(final Long bytesReceived) {
if (bytesReceived == null) {
throw new IllegalArgumentException("Argument 'bytesReceived' can not be null.");
}
if (bytesReceived < 0) {
throw new IllegalArgumentException("Argument 'bytesReceived' can not be smaller than 0.");
}
this.bytesReceived = bytesReceived;
return this;
}
/**
* Sets the sent bytes including the headers. If no sent bytes were logged, the given argument should be zero.
*
* @param bytesSend
* the bytes sent or <code>0</code>
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @throws IllegalArgumentException
* if the given argument is smaller than <code>0</code>
* @return itself, for chaining
*/
public LogEntryBuilder bytesSent(final Long bytesSend) {
if (bytesSend == null) {
throw new IllegalArgumentException("Argument 'bytesSend' can not be null.");
}
if (bytesSend < 0) {
throw new IllegalArgumentException("Argument 'bytesSend' can not be smaller than 0.");
}
this.bytesSent = bytesSend;
return this;
}
/**
* Sets the connection status when response was completed. If no connection status was logged, the given argument
* should be an <code>HttpConnectionStatus.UNKNOWN</code>.
*
* @param connectionStatus
* the connection status
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder connectionStatus(final HttpConnectionStatus connectionStatus) {
if (connectionStatus == null) {
throw new IllegalArgumentException("Argument 'connectionStatus' can not be null.");
}
this.connectionStatus = connectionStatus;
return this;
}
/**
* Sets the filename of the log file.
*
* @param filename
* the filename of the log file
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder filename(final String filename) {
if (filename == null) {
throw new IllegalArgumentException("Argument 'filename' can not be null.");
}
this.filename = filename;
return this;
}
@Override
public Long getBytesReceived() {
return bytesReceived;
}
@Override
public Long getBytesSent() {
return bytesSent;
}
@Override
public HttpConnectionStatus getConnectionStatus() {
return connectionStatus;
}
public Set<HttpCookie> getCookies() {
return cookies;
}
@Override
public String getFilename() {
return filename;
}
@Override
public HttpStatus getLastStatusCode() {
return lastStatusCode;
}
@Override
public String getLocalIpAddress() {
return localIpAddress;
}
@Override
public Integer getProcessId() {
return processId;
}
@Override
public String getQueryString() {
return queryString;
}
@Override
public String getRemoteHost() {
return remoteHost;
}
@Override
public String getRemoteIpAddress() {
return remoteIpAddress;
}
@Override
public String getRemoteLogname() {
return remoteLogname;
}
@Override
public String getRemoteUser() {
return remoteUser;
}
@Override
public Set<ReadableHttpRequestHeaderField> getRequestHeaders() {
return requestHeaders;
}
@Override
public Long getRequestInMillis() {
return requestInMillis;
}
@Override
public HttpRequestMethod getRequestMethod() {
return requestMethod;
}
@Override
public String getRequestProtocol() {
return requestProtocol;
}
@Override
public Date getRequestTime() {
return requestTime;
}
@Override
public Set<ReadableHttpResponseHeaderField> getResponseHeaders() {
return responseHeaders;
}
@Override
public Long getResponseInBytes() {
return responseInBytes;
}
@Override
public String getServerName() {
return serverName;
}
@Override
public Integer getServerPort() {
return serverPort;
}
@Override
public HttpStatus getStatusCode() {
return statusCode;
}
@Override
public String getUrlPath() {
return urlPath;
}
/**
* Sets the status code of the last HTTP request. When internal redirects are made, the final status should be set
* with this method.
*
* @param lastStatusCode
* the status code of the last HTTP request
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder lastStatusCode(final HttpStatus lastStatusCode) {
if (lastStatusCode == null) {
throw new IllegalArgumentException("Argument 'lastStatusCode' can not be null.");
}
this.lastStatusCode = lastStatusCode;
return this;
}
/**
* Sets the local (usually the servers) IP address.
*
* @param localIpAddress
* the local IP address
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder localIpAddress(final String localIpAddress) {
if (localIpAddress == null) {
throw new IllegalArgumentException("Argument 'localIpAddress' can not be null.");
}
this.localIpAddress = localIpAddress;
return this;
}
/**
* Sets the ID of the process that serviced the request. If no process ID was logged, the given argument should be
* zero.
*
* @param processId
* the ID of the process
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @throws IllegalArgumentException
* if the given argument is smaller than <code>0</code>
* @return itself, for chaining
*/
public LogEntryBuilder processId(final Integer processId) {
if (processId == null) {
throw new IllegalArgumentException("Argument 'processId' can not be null.");
}
if (processId < 0) {
throw new IllegalArgumentException("Argument 'processId' can not be smaller than 0.");
}
this.processId = processId;
return this;
}
/**
* Sets the query string (prepended with a <code>?</code> if a query string exists, otherwise an empty string) of
* the requested URL.<br>
* <br>
* The query string is the part of a Uniform Resource Locator (URL) that contains data to be passed to web
* applications.<br>
* <br>
* For example: <code>?param1=value1¶m2=value2</code>
*
* @param queryString
* the query string
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder queryString(final String queryString) {
if (queryString == null) {
throw new IllegalArgumentException("Argument 'queryString' can not be null.");
}
this.queryString = queryString;
return this;
}
/**
* Sets the client IP address (like 93.71.122.14) or the corresponding hostname (like <code>jacclog.sf.net</code>)
* of the remote user requesting the resource.<br>
* <br>
* For performance reasons, many web servers are configured not to do hostname lookups on the remote host. This
* means that all you end up within the log file is a bunch of IP addresses.
*
* @param remoteHost
* the remote IP address or hostname
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder remoteHost(final String remoteHost) {
if (remoteHost == null) {
throw new IllegalArgumentException("Argument 'remoteHost' can not be null.");
}
this.remoteHost = remoteHost;
return this;
}
/**
* Sets the client IP address (like 93.71.122.14) of the remote user requesting the resource.
*
* @param remoteIpAddress
* the remote IP address
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder remoteIpAddress(final String remoteIpAddress) {
if (remoteIpAddress == null) {
throw new IllegalArgumentException("Argument 'remoteIpAddress' can not be null.");
}
this.remoteIpAddress = remoteIpAddress;
return this;
}
/**
* Sets the remote logname (from identd, if supplied).
*
* @param remoteLogname
* the remote logname
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder remoteLogname(final String remoteLogname) {
if (remoteLogname == null) {
throw new IllegalArgumentException("Argument 'remoteLogname' can not be null.");
}
this.remoteLogname = remoteLogname;
return this;
}
/**
* Sets the remote user name.
*
* @param remoteUser
* the remote user name
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder remoteUser(final String remoteUser) {
if (remoteUser == null) {
throw new IllegalArgumentException("Argument 'remoteUser' can not be null.");
}
this.remoteUser = remoteUser;
return this;
}
/**
* Sets the request in milliseconds.
*
* @param requestInMillis
* the request in milliseconds
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder requestInMillis(final Long requestInMillis) {
if (requestInMillis == null) {
throw new IllegalArgumentException("Argument 'requestInMillis' can not be null.");
}
if (requestInMillis < 0) {
throw new IllegalArgumentException("Argument 'requestInMillis' can not be smaller than 0.");
}
this.requestInMillis = requestInMillis;
return this;
}
/**
* Sets the logged HTTP request method. If it is a valid method the type will be a field of
* <code>HttpRequestMethod</code>, otherwise it will be an instance of <code>UnknownHttpRequestMethod</code>.
*
* @param requestMethod
* the HTTP request method
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder requestMethod(final HttpRequestMethod requestMethod) {
if (requestMethod == null) {
throw new IllegalArgumentException("Argument 'requestMethod' can not be null.");
}
this.requestMethod = requestMethod;
return this;
}
/**
* Sets the used HTTP protocol of the request.
*
* @param requestProtocol
* the HTTP protocol
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder requestProtocol(final String requestProtocol) {
if (requestProtocol == null) {
throw new IllegalArgumentException("Argument 'requestProtocol' can not be null.");
}
this.requestProtocol = requestProtocol;
return this;
}
/**
* Sets the time the request was received.
*
* @param requestTime
* the request time
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder requestTime(final Date requestTime) {
if (requestTime == null) {
throw new IllegalArgumentException("Argument 'requestTime' can not be null.");
}
this.requestTime = requestTime;
return this;
}
/**
* Sets the size of response in bytes, excluding HTTP headers.
*
* @param responseInBytes
* the response in bytes
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder responseInBytes(final Long responseInBytes) {
if (responseInBytes == null) {
throw new IllegalArgumentException("Argument 'responseInBytes' can not be null.");
}
if (responseInBytes < 0) {
throw new IllegalArgumentException("Argument 'responseInBytes' can not be smaller than 0.");
}
this.responseInBytes = responseInBytes;
return this;
}
/**
* Sets the server name according to the UseCanonicalName setting.
*
* @param serverName
* the server name
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder serverName(final String serverName) {
if (serverName == null) {
throw new IllegalArgumentException("Argument 'serverName' can not be null.");
}
this.serverName = serverName;
return this;
}
/**
* Sets the canonical port of the server serving the request.
*
* @param serverPort
* the server port
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder serverPort(final Integer serverPort) {
if (serverPort == null) {
throw new IllegalArgumentException("Argument 'serverPort' can not be null.");
}
this.serverPort = serverPort;
return this;
}
/**
* Sets the status code of the <strong>original</code> request not of the redirected one.
*
* @param statusCode
* the status code
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder statusCode(final HttpStatus statusCode) {
if (statusCode == null) {
throw new IllegalArgumentException("Argument 'statusCode' can not be null.");
}
this.statusCode = statusCode;
return this;
}
/**
* Sets the URL path requested, not including any query string.
*
* @param urlPath
* the URL path
* @throws IllegalArgumentException
* if the given argument is <code>null</code>
* @return itself, for chaining
*/
public LogEntryBuilder urlPath(final String urlPath) {
if (urlPath == null) {
throw new IllegalArgumentException("Argument 'urlPath' can not be null.");
}
this.urlPath = urlPath;
return this;
}
}