package org.juxtasoftware.resource; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; import org.juxtasoftware.dao.JuxtaXsltDao; import org.juxtasoftware.dao.PageMarkDao; import org.juxtasoftware.dao.WitnessDao; import org.juxtasoftware.model.JuxtaXslt; import org.juxtasoftware.model.PageMark; import org.juxtasoftware.model.Usage; import org.juxtasoftware.model.Witness; import org.juxtasoftware.service.WitnessRemover; import org.juxtasoftware.util.ConversionUtils; import org.juxtasoftware.util.RangedTextReader; import org.juxtasoftware.util.ftl.FileDirective; import org.juxtasoftware.util.ftl.FileDirectiveListener; import org.restlet.data.Status; import org.restlet.representation.Representation; import org.restlet.resource.Delete; import org.restlet.resource.Get; import org.restlet.resource.Put; 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.JsonObject; import com.google.gson.JsonParser; import eu.interedition.text.Range; /** * Server resource for interacting with Witness documents. * * @author loufoster * */ @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class WitnessResource extends BaseResource { private Witness witness = null; private Range range = null; @Autowired private WitnessDao witnessDao; @Autowired private WitnessRemover remover; @Autowired private JuxtaXsltDao xsltDao; @Autowired private PageMarkDao pageMarkDao; /** * Extract the text ID and range info from the request attributes */ @Override protected void doInit() throws ResourceException { super.doInit(); Long id = getIdFromAttributes("witnessId"); if ( id == null ) { return; } this.witness = this.witnessDao.find(id); if ( validateModel(this.witness) == false ) { 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 { getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid Range specified"); } } else { this.range = new Range(0, this.witness.getText().getLength()); } } @Get("txt") public Representation toPlainText() { try { final RangedTextReader reader = new RangedTextReader(); reader.read( this.witnessDao.getContentStream(this.witness), this.range ); return toTextRepresentation(reader.toString()); } catch (IOException e) { setStatus(Status.SERVER_ERROR_INTERNAL); return toTextRepresentation("Error retrieving witness: "+e.getMessage()); } } @Get("json") public Representation toJson() { try { final File wit = witnessToHtml(); FileReader fr = new FileReader(wit); JsonObject obj = new JsonObject(); obj.addProperty("id", this.witness.getId()); obj.addProperty("name", this.witness.getName()); obj.addProperty("sourceId", this.witness.getSourceId()); obj.addProperty("xsltId", this.witness.getXsltId()); obj.addProperty("content", IOUtils.toString(fr)); obj.addProperty("hasLineNumbers", this.pageMarkDao.hasLineNumbers(this.witness.getId()) ); obj.addProperty("hasPageBreaks", this.pageMarkDao.hasBreaks(this.witness.getId()) ); if ( this.witness.getUpdated() != null && this.witness.getUpdated().after(this.witness.getCreated() ) ) { obj.addProperty("xmlTemplate", "Custom"); } else { if ( this.witness.getXsltId() != null ) { final JuxtaXslt xslt = this.xsltDao.find(this.witness.getXsltId()); if ( xslt.getXslt().contains("tei:")) { obj.addProperty("xmlTemplate", "TEI Default"); } else if ( xslt.getXslt().contains("ramheader")) { obj.addProperty("xmlTemplate", "RAM Default"); } else if ( xslt.getXslt().contains("m_e")) { obj.addProperty("xmlTemplate", "Juxta Default"); } else { obj.addProperty("xmlTemplate", "XML Default"); } } } wit.delete(); Gson gson = new Gson(); return toJsonRepresentation(gson.toJson(obj)); } catch (IOException e) { setStatus(Status.SERVER_ERROR_INTERNAL); return toTextRepresentation("Error retrieving witness: "+e.getMessage()); } } @Get("html") public Representation toHtml() { try { final File wit = witnessToHtml(); FileDirective fd = new FileDirective(); fd.setListener( new FileDirectiveListener() { @Override public void fileReadComplete(File file) { wit.delete(); } }); Map<String,Object> map = new HashMap<String,Object>(); map.put("name", witness.getName()); map.put("witnessFile", wit); map.put("fileReader", fd); map.put("page", "witness"); map.put("title", "Juxta Witness: "+witness.getName()); return toHtmlRepresentation("witness.ftl", map); } catch (IOException e) { setStatus(Status.SERVER_ERROR_INTERNAL); return toTextRepresentation("Error retrieving witness: "+e.getMessage()); } } private File witnessToHtml() throws IOException { Reader reader = this.witnessDao.getContentStream(this.witness); List<PageMark> marks = this.pageMarkDao.find(this.witness.getId() ); return ConversionUtils.witnessToHtml(reader, this.range, marks); } /** * Accept json data to update the name of a witness. * format: { "name": "newName" } * @param jsonStr */ @Put("json") public Representation rename( final String jsonStr ) { JsonParser parser = new JsonParser(); JsonObject jsonObj = parser.parse(jsonStr).getAsJsonObject(); String name = jsonObj.get("name").getAsString(); // make sure name chages don't cause conflicts if ( this.witness.getName().equals(name) == false ) { if ( this.witnessDao.exists(this.workspace,name)) { setStatus(Status.CLIENT_ERROR_CONFLICT); return toTextRepresentation("Set "+name+" already exists in workspace " +this.workspace.getName()); } } this.witnessDao.rename(this.witness, name); return toTextRepresentation( this.witness.getId().toString()); } /** * Delete the specified witness */ @Delete public Representation deleteWitness() { try { LOG.info("Delete witness "+this.witness.getId()); List<Usage> usage = this.remover.remove(this.witness); Gson gson = new Gson(); return toJsonRepresentation( gson.toJson(usage) ); } catch (ResourceException e) { Status statusCode = e.getStatus(); setStatus( statusCode); return toTextRepresentation( e.getStatus().getDescription() ); } } }