package org.juxtasoftware.resource; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.juxtasoftware.dao.AlignmentDao; import org.juxtasoftware.dao.ComparisonSetDao; import org.juxtasoftware.dao.JuxtaAnnotationDao; import org.juxtasoftware.dao.QNameFilterDao; import org.juxtasoftware.dao.WitnessDao; import org.juxtasoftware.model.Alignment; import org.juxtasoftware.model.Alignment.AlignedAnnotation; import org.juxtasoftware.model.AlignmentConstraint; import org.juxtasoftware.model.ComparisonSet; import org.juxtasoftware.model.JuxtaAnnotation; import org.juxtasoftware.model.QNameFilter; import org.juxtasoftware.model.Witness; import org.juxtasoftware.util.AlignmentSerializer; import org.restlet.data.Status; import org.restlet.representation.Representation; import org.restlet.resource.Get; 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; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import eu.interedition.text.Name; import eu.interedition.text.NameRepository; import eu.interedition.text.Range; import eu.interedition.text.mem.SimpleName; @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class AlignmentsResource extends BaseResource { @Autowired private AlignmentDao alignmentDao; @Autowired private ComparisonSetDao setDao; @Autowired private JuxtaAnnotationDao annotationDao; @Autowired private QNameFilterDao filterDao; @Autowired private NameRepository nameRepo; @Autowired private WitnessDao witnessDao; private ComparisonSet set = null; private QNameFilter filter = null; private Range range = null; @Override protected void doInit() throws ResourceException { super.doInit(); Long setId = getIdFromAttributes("setId"); if ( setId == null ) { return; } this.set = this.setDao.find( setId); if ( validateModel(this.set) == false ) { return; } // get by filter? if (getQuery().getValuesMap().containsKey("filter") ) { String filterName = getQuery().getValuesMap().get("filter"); this.filter = this.filterDao.find(filterName); if ( this.filter == null ) { setStatus(Status.CLIENT_ERROR_NOT_FOUND, "Invalid filter name \""+filterName+"\""); return; } } // was a range set requested? if (getQuery().getValuesMap().containsKey("range") ) { String rangeInfo = getQuery().getValues("range"); String ranges[] = rangeInfo.split(","); if ( ranges.length == 2) { this.range = new Range( Integer.parseInt(ranges[0]), Integer.parseInt(ranges[1]) ); } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid Range specified"); } } } @Get("html") public Representation toHtml() { List<Alignment> aligns = getAlignments(); Map<String,Object> map = new HashMap<String,Object>(); map.put("setName", set.getName()); map.put("setId", set.getId()); map.put("alignments", aligns); map.put("page", "set"); map.put("title", "Juxta \""+set.getName()+"\" Differences"); return toHtmlRepresentation("alignments.ftl",map); } private List<Alignment> getAlignments() { AlignmentConstraint constraint = new AlignmentConstraint( this.set ); constraint.setFilter( this.filter ); constraint.setRange( this.range ); List<Alignment> aligns = this.alignmentDao.list( constraint ); return aligns; } @Get("json") public Representation toJson() { List<Alignment> aligns = getAlignments(); Gson gson = new GsonBuilder() .registerTypeAdapter(Alignment.class, new AlignmentSerializer()) .create(); String json = gson.toJson(aligns); return toJsonRepresentation(json); } @Post("json") public Representation acceptJson( final String jsonStr ) { LOG.info("Create alignments from "+jsonStr); JsonParser parser = new JsonParser(); JsonArray jsonArray = null; try { jsonArray = parser.parse(jsonStr).getAsJsonArray(); } catch ( Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation("Malformed json payload"); } List<Alignment> alignments = new ArrayList<Alignment>(); for ( Iterator<JsonElement> itr = jsonArray.iterator(); itr.hasNext(); ) { JsonObject jsonObj = itr.next().getAsJsonObject(); Name linkQname = null; List<JuxtaAnnotation> annotations = new ArrayList<JuxtaAnnotation>(); String editDistance = null; try { JsonObject nameObj = jsonObj.get("name").getAsJsonObject(); linkQname = getQnameFromJson(nameObj); if ( jsonObj.has("editDistance")) { editDistance = jsonObj.get("editDistance").getAsString(); } // ensure that 2 entries exist for annotation JsonArray annoArray = jsonObj.get("annotations").getAsJsonArray(); if ( annoArray.size() != 2 ) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation("Incorrect number of annotations in JSON payload"); } // extract/create annotation for ( int i=0; i<2; i++ ) { if ( annoArray.get(i).isJsonObject() ) { JuxtaAnnotation a = createAnnotation( annoArray.get(i).getAsJsonObject() ); if ( a != null ) { annotations.add( a ); } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation("Invalid json payload for annotation"); } } else { JuxtaAnnotation a = lookupAnnotation(annoArray.get(i).getAsLong() ); if ( a != null) { annotations.add( a ); } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation("Invalid annotation ID specified for alignment"); } } } } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation("Missing required data in json payload"); } Alignment align = new Alignment(); align.setName( linkQname ); if ( editDistance != null ) { align.setEditDistance( Integer.parseInt(editDistance) ); } else { align.setEditDistance( -1 ); } align.setComparisonSetId(this.set.getId()); align.setManual(); align.addAnnotation( new AlignedAnnotation(annotations.get(0)) ); align.addAnnotation( new AlignedAnnotation(annotations.get(1)) ); if ( align.getAnnotations().size() != 2) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation("Invalid annotations specified in json payload"); } alignments.add( align ); } int created = this.alignmentDao.create(alignments); return toTextRepresentation(""+created); } private JuxtaAnnotation lookupAnnotation(long id) { return this.annotationDao.find(id, false); } private JuxtaAnnotation createAnnotation(JsonObject annoObj) { Name qname = null; Range range =null; Witness witness = null; try { JsonObject nameObj = annoObj.get("name").getAsJsonObject(); qname = this.nameRepo.get( new SimpleName( nameObj.get("namespace").getAsString(), nameObj.get("localName").getAsString() ) ); JsonObject rangeObj = annoObj.get("range").getAsJsonObject(); range = new Range(rangeObj.get("start").getAsLong(), rangeObj.get("end").getAsLong()); Long id = annoObj.get("witnessId").getAsLong(); witness = this.witnessDao.find(id); } catch (Exception e) { return null; } JuxtaAnnotation ano = new JuxtaAnnotation( this.set.getId(), witness, qname, range); ano.setManual(); Long id = this.annotationDao.create(ano); ano.setId(id); return ano; } private Name getQnameFromJson(JsonObject nameObj) { // note: this creates a name if it does not exist Name name = this.nameRepo.get( new SimpleName( nameObj.get("namespace").getAsString(), nameObj.get("localName").getAsString()) ); return name; } }