/*******************************************************************************
* Copyright (c) 2011 Subgraph.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Subgraph - initial API and implementation
******************************************************************************/
package com.subgraph.vega.internal.model.requests;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import com.db4o.ObjectContainer;
import com.db4o.events.Event4;
import com.db4o.events.EventListener4;
import com.db4o.events.EventRegistry;
import com.db4o.events.EventRegistryFactory;
import com.db4o.events.ObjectInfoEventArgs;
import com.db4o.query.Predicate;
import com.db4o.query.Query;
import com.subgraph.vega.api.http.requests.IHttpResponse;
import com.subgraph.vega.api.model.conditions.IHttpConditionSet;
import com.subgraph.vega.api.model.requests.IRequestLog;
import com.subgraph.vega.api.model.requests.IRequestLogRecord;
import com.subgraph.vega.api.model.requests.IRequestLogUpdateListener;
import com.subgraph.vega.internal.model.conditions.HttpConditionSet;
public class RequestLog implements IRequestLog {
private final ObjectContainer database;
private final RequestLogId requestLogId;
private final HttpMessageCloner cloner;
private final List<RequestLogListener> listenerList = new ArrayList<RequestLogListener>();
private final Object lock = new Object();
public RequestLog(final ObjectContainer database) {
this.database = database;
this.requestLogId = getRequestLogId(database);
this.cloner = new HttpMessageCloner(database);
final EventRegistry registry = EventRegistryFactory.forObjectContainer(database);
registry.activated().addListener(new EventListener4<ObjectInfoEventArgs> () {
@Override
public void onEvent(Event4<ObjectInfoEventArgs> arg0, ObjectInfoEventArgs args) {
final Object ob = args.object();
if(ob instanceof RequestLogResponse) {
final RequestLogResponse r = (RequestLogResponse) ob;
r.setDatabase(database);
} else if(ob instanceof RequestLogEntityEnclosingRequest) {
final RequestLogEntityEnclosingRequest r = (RequestLogEntityEnclosingRequest) ob;
r.setDatabase(database);
}
}
});
}
private RequestLogId getRequestLogId(ObjectContainer database) {
List<RequestLogId> result = database.query(RequestLogId.class);
if(result.size() == 0) {
RequestLogId rli = new RequestLogId();
database.store(rli);
return rli;
} else if(result.size() == 1) {
return result.get(0);
} else {
throw new IllegalStateException("Database corrupted, found multiple RequestLogId instances");
}
}
@Override
public long allocateRequestId() {
final long id = requestLogId.allocateId();
database.store(requestLogId);
return id;
}
@Override
public long addRequestResponse(IHttpResponse response) {
if (response.getRequestId() != -1) {
return response.getRequestId();
}
final long id = allocateRequestId();
final HttpRequest newRequest = cloner.copyRequest(response.getOriginalRequest());
final HttpResponse newResponse = cloner.copyResponse(response.getRawResponse());
database.store(newRequest);
database.store(newResponse);
final RequestLogRecord record = new RequestLogRecord(id, newRequest, newResponse, response.getHost(), response.getRequestMilliseconds());
synchronized(lock){
database.store(record);
filterNewRecord(record);
}
response.setRequestId(id);
return id;
}
private void filterNewRecord(IRequestLogRecord record) {
for(RequestLogListener listener: listenerList) {
listener.filterRecord(record);
}
}
@Override
public RequestLogRecord lookupRecord(final long requestId) {
synchronized(this) {
List<RequestLogRecord> result = database.query(new Predicate<RequestLogRecord>() {
private static final long serialVersionUID = 1L;
@Override
public boolean match(RequestLogRecord record) {
return record.requestId == requestId;
}
});
if(result.size() == 0)
return null;
else if(result.size() == 1)
return result.get(0);
else
throw new IllegalStateException("Database corrupted, found multiple RequestLogRecords for id == "+ requestId);
}
}
@Override
public List<IRequestLogRecord> getAllRecords() {
if(!hasRecords()) {
return Collections.emptyList();
}
final Query query = database.query();
query.constrain(IRequestLogRecord.class);
return query.execute();
}
private boolean hasRecords() {
final Query query = database.query();
query.constrain(IRequestLogRecord.class);
return query.execute().size() > 0;
}
public List<IRequestLogRecord> getRecordsByConditionSet(IHttpConditionSet conditionFilter) {
if(conditionFilter instanceof HttpConditionSet) {
return ((HttpConditionSet)conditionFilter).filterRequestLog(database);
} else {
return Collections.emptyList();
}
}
@Override
public void addUpdateListener(IRequestLogUpdateListener callback) {
synchronized(lock) {
listenerList.add(new RequestLogListener(callback, null, getAllRecords().size()));
}
}
@Override
public void addUpdateListener(IRequestLogUpdateListener callback, IHttpConditionSet conditionFilter) {
synchronized(lock) {
listenerList.add(new RequestLogListener(callback, conditionFilter, getRecordsByConditionSet(conditionFilter).size()));
}
}
@Override
public void removeUpdateListener(IRequestLogUpdateListener callback) {
synchronized (lock) {
final Iterator<RequestLogListener> it = listenerList.iterator();
while(it.hasNext()) {
RequestLogListener listener = it.next();
if(listener.getListenerCallback() == callback)
it.remove();
}
}
}
}