package org.juxtasoftware.resource;
import java.io.IOException;
import java.util.Date;
import org.juxtasoftware.dao.ComparisonSetDao;
import org.juxtasoftware.model.CollatorConfig;
import org.juxtasoftware.model.ComparisonSet;
import org.juxtasoftware.service.Tokenizer;
import org.juxtasoftware.util.BackgroundTask;
import org.juxtasoftware.util.BackgroundTaskCanceledException;
import org.juxtasoftware.util.BackgroundTaskStatus;
import org.juxtasoftware.util.TaskManager;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.Post;
import org.restlet.resource.ResourceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
/**
* Resource to initiate, monitor and control the tokenizer
*
* @author lfoster
*
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class TokenizerResource extends BaseResource {
@Autowired private ComparisonSetDao comparisonSetDao;
@Autowired private Tokenizer tokenizer;
@Autowired private TaskManager taskManager;
private ComparisonSet set;
@Override
protected void doInit() throws ResourceException {
super.doInit();
String idStr = (String) getRequestAttributes().get("id");
Long id = null;
try {
id = Long.parseLong(idStr);
} catch (NumberFormatException e ) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid source id");
return;
}
this.set = this.comparisonSetDao.find(id);
if ( validateModel(this.set) == false) {
return;
}
}
@Post
public Representation acceptPost() {
LOG.info("Tokenize set "+this.set.getId() );
int witCnt = this.comparisonSetDao.getWitnesses(this.set).size();
if ( witCnt < 2 ) {
this.set.setStatus(ComparisonSet.Status.ERROR);
this.comparisonSetDao.update(this.set);
setStatus(Status.CLIENT_ERROR_PRECONDITION_FAILED);
return toTextRepresentation("Collation requires at least 2 witnesses. This set has "+witCnt+".");
}
final String taskId = generateTaskName(this.set.getId());
this.taskManager.submit( new TokenizeTask(taskId) );
return toTextRepresentation( taskId );
}
private String generateTaskName(final Long setId ) {
final int prime = 31;
int result = 1;
result = prime * result + setId.hashCode();
return "tokenize-"+result;
}
/**
* Task to asynchronously execute the tokenization
*/
private class TokenizeTask implements BackgroundTask {
private final String name;
private BackgroundTaskStatus status;
private final CollatorConfig config;
private Date startDate;
private Date endDate;
public TokenizeTask(final String name ) {
this.name = name;
this.status = new BackgroundTaskStatus( this.name );
this.config = comparisonSetDao.getCollatorConfig( set);
this.startDate = new Date();
}
@Override
public Type getType() {
return BackgroundTask.Type.TOKENIZE;
}
@Override
public void run() {
try {
LOG.info("Begin task "+this.name);
this.status.begin();
tokenizer.tokenize( TokenizerResource.this.set, this.config, this.status);
LOG.info("task "+this.name+" COMPLETE");
this.endDate = new Date();
} catch (IOException e) {
LOG.error(this.name+" task failed", e.toString());
this.status.fail(e.toString());
this.endDate = new Date();
} catch ( BackgroundTaskCanceledException e) {
LOG.info( this.name+" task was canceled");
this.endDate = new Date();
} catch (Exception e) {
LOG.error(this.name+" task failed", e);
this.status.fail(e.toString());
this.endDate = new Date();
}
}
@Override
public void cancel() {
this.status.cancel();
}
@Override
public BackgroundTaskStatus.Status getStatus() {
return this.status.getStatus();
}
@Override
public String getName() {
return this.name;
}
@Override
public Date getEndTime() {
return this.endDate;
}
@Override
public Date getStartTime() {
return this.startDate;
}
@Override
public String getMessage() {
return this.status.getNote();
}
}
}