package org.juxtasoftware.resource; import java.util.Set; import org.juxtasoftware.dao.JuxtaXsltDao; import org.juxtasoftware.dao.SourceDao; import org.juxtasoftware.dao.WitnessDao; import org.juxtasoftware.model.JuxtaXslt; import org.juxtasoftware.model.Source; import org.juxtasoftware.model.Workspace; import org.juxtasoftware.service.SourceTransformer; import org.juxtasoftware.service.importer.JuxtaXsltFactory; import org.juxtasoftware.service.importer.XmlTemplateParser; import org.juxtasoftware.service.importer.XmlTemplateParser.TemplateInfo; import org.juxtasoftware.util.NamespaceExtractor; import org.juxtasoftware.util.NamespaceExtractor.NamespaceInfo; import org.juxtasoftware.util.NamespaceExtractor.XmlType; import org.restlet.data.Status; import org.restlet.representation.Representation; import org.restlet.resource.Post; 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.JsonObject; import com.google.gson.JsonParser; /** * Resource used to transform source documents into * texts by applying a parsing template * * @author lfoster * */ @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class Transformer extends BaseResource { @Autowired private SourceDao sourceDao; @Autowired private JuxtaXsltDao xsltDao; @Autowired private WitnessDao witnessDao; @Autowired private SourceTransformer transformer; @Autowired private XmlTemplateParser templateParser; @Autowired private JuxtaXsltFactory xsltFactory; /** * Transform the source identified by <code>sourceID</id> into a new * text using parsing template <code>templateID</code> * * @param jsonString * @return */ @Post("json") public Representation transformSource( final String jsonString ) { LOG.info("Transform post data: "+jsonString); // Get and validate the source from json JsonParser parser = new JsonParser(); JsonObject json = parser.parse(jsonString).getAsJsonObject(); Long sourceId = null; try { sourceId = json.get("source").getAsLong(); } catch (NumberFormatException e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation( "Invalid source id" ); } Source srcDoc = this.sourceDao.find(this.workspace.getId(), sourceId); if ( validateModel(srcDoc) == false ) { getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND); return toTextRepresentation( "Invalid source "+sourceId); } // if an alternate name for the parsed witness was passed // get it; otherwise its just the src file minus extenson String finalName = ""; if ( json.has("finalName")) { finalName = json.get("finalName").getAsString(); } else { finalName = srcDoc.getName(); int pos = finalName.lastIndexOf('.'); if ( pos > -1 ) { finalName = finalName.substring(0, pos); } } // if requested, get the xslt transform JuxtaXslt xslt = null; boolean newXslt = false; Workspace pub = this.workspaceDao.getPublic(); if ( json.has("xslt") ) { Long xsltId = json.get("xslt").getAsLong(); xslt = this.xsltDao.find(xsltId); } else { // if none specifed and source is xml, generate a new XSLT // based in the starter template if ( srcDoc.getType().equals(Source.Type.XML)) { try { newXslt = true; xslt = createXsltFromTemplate(srcDoc, finalName); } catch (Exception e) { setStatus(Status.SERVER_ERROR_INTERNAL); return toTextRepresentation("Unable to generate XSLT for transform: "+e.toString()); } } } // validate template/workspace match (except public) if ( xslt != null && this.workspace.getId().equals(xslt.getWorkspaceId()) == false && xslt.getWorkspaceId().equals(pub.getId())==false){ setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return toTextRepresentation( "Requested XSLT does not exist"); } // prevent duplicate witnesses from being created if ( this.witnessDao.exists(this.workspace, finalName) ) { setStatus(Status.CLIENT_ERROR_CONFLICT); if ( newXslt ) { this.xsltDao.delete(xslt); } return toTextRepresentation( "Witness '"+finalName+"' already exists"); } try { Long witnessId = this.transformer.transform(srcDoc, xslt, finalName); return toTextRepresentation( witnessId.toString() ); } catch (Exception e) { LOG.error("Caught Excepion: unable to transform source", e); setStatus(Status.SERVER_ERROR_INTERNAL); if ( newXslt ) { this.xsltDao.delete(xslt); } return toTextRepresentation("Transform Failed: "+e.getMessage()); } } private JuxtaXslt createXsltFromTemplate(final Source src, final String name) throws Exception { // if a document has multiple namespaces, do not try to apply TEI or ram templates to it, just generic Set<NamespaceInfo> namespaces = NamespaceExtractor.extract( this.sourceDao.getContentReader(src) ); if ( namespaces.size() > 1 ) { return this.xsltFactory.create(this.workspace.getId(), name ); } else { // get the NS info.... NamespaceInfo nsInfo = NamespaceInfo.createBlankNamespace(); if ( namespaces.size() == 1 ) { nsInfo = (NamespaceInfo)namespaces.toArray()[0]; } // create XSLT based on a scan thru the src to determine XML type XmlType xmlType = NamespaceExtractor.determineXmlType( this.sourceDao.getContentReader(src) ); LOG.info(src.toString()+" appears to be XmlType: "+xmlType.toString()); switch (xmlType ) { case TEI: return getTeiXslt( name, nsInfo); case RAM: return getRamXslt( name, nsInfo); case JUXTA: return getJuxtaXslt( name, nsInfo); default: return this.xsltFactory.create(this.workspace.getId(), name ); } } } private JuxtaXslt getJuxtaXslt(String name, NamespaceInfo nsInfo) throws Exception { this.templateParser.parse( ClassLoader.getSystemResourceAsStream("juxta-document.xml") ); TemplateInfo jxInfo = this.templateParser.getTemplates().get(0); return this.xsltFactory.createFromTemplateInfo(this.workspace.getId(), name, jxInfo, nsInfo); } private JuxtaXslt getTeiXslt(final String name, final NamespaceInfo namespace ) throws Exception { this.templateParser.parse( ClassLoader.getSystemResourceAsStream("tei-template.xml") ); TemplateInfo teiInfo = this.templateParser.getTemplates().get(0); namespace.setDefaultPrefix("tei"); return this.xsltFactory.createFromTemplateInfo(this.workspace.getId(), name, teiInfo, namespace); } private JuxtaXslt getRamXslt(final String name, final NamespaceInfo namespace ) throws Exception { this.templateParser.parse( ClassLoader.getSystemResourceAsStream("ram.xml") ); TemplateInfo ramInfo = this.templateParser.getTemplates().get(0); return this.xsltFactory.createFromTemplateInfo(this.workspace.getId(), name, ramInfo, namespace); } }