package org.emile.cirilo.business;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.apache.log4j.Logger;
import org.emile.cirilo.Common;
import org.emile.cirilo.ServiceNames;
import org.emile.cirilo.User;
import org.emile.cirilo.ecm.repository.Repository;
import org.emile.cirilo.ecm.templates.TemplateSubsystem;
import org.emile.cirilo.utils.eXist;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Attribute;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.JDOMResult;
import org.jdom.transform.JDOMSource;
import org.jdom.xpath.XPath;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.modules.XMLResource;
import voodoosoft.jroots.core.CPropertyService;
import voodoosoft.jroots.core.CServiceProvider;
import voodoosoft.jroots.dialog.CDefaultGuiAdapter;
public class MEI {
private static Logger log = Logger.getLogger(MEI.class);
private Document mei;
private File file;
private String raw;
private String collection;
private Format format;
private XMLOutputter outputter;
private FileWriter logger;
private String PID;
private TemplateSubsystem temps;
private String URI;
private User user;
private SAXBuilder builder;
private boolean onlyValidate;
private boolean mode;
private boolean isCustomized;
private CPropertyService props;
private String xuser;
public MEI(FileWriter logger, boolean validate, boolean mode) {
try {
temps = (TemplateSubsystem) CServiceProvider.getService(ServiceNames.TEMPLATESUBSYSTEM);
props = (CPropertyService) CServiceProvider.getService(ServiceNames.PROPERTIES);
user = (User) CServiceProvider.getService(ServiceNames.CURRENT_USER);
URI = user.getExistUrl();
format = Format.getRawFormat();
format.setEncoding("UTF-8");
outputter = new XMLOutputter(format);
this.logger = logger;
this.onlyValidate = validate;
this.mode = mode;
this.raw = null;
this.builder = new SAXBuilder();
this.xuser = user.getUser();
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
}
}
public void setUser (String u) {this.xuser = u;}
public boolean set (String file, boolean eXist) {
try {
this.PID = "";
if (!eXist) {
this.file = new File (file);
this.collection="";
if (this.file.exists()) {
this.mei = builder.build( this.file );
validate();
}
return this.file.exists();
} else {
eXist eX = new eXist(file);
org.xmldb.api.base.Collection collection = DatabaseManager.getCollection( URI + eX.getCollection(), user.getExistUser(), user.getExistPasswd() );
XMLResource res = (XMLResource) collection.getResource(eX.getStream());
this.mei = builder.build( new StringReader( (String) res.getContent()));
validate();
collection.close();
this.collection = file;
return true;
}
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
return false;
}
}
public void validate() {
try {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
StreamSource is = null;
JDOMResult out = new JDOMResult();
Transformer transformer;
XPath xpath = XPath.newInstance("/score-partwise");
Element score_partwise = (Element) xpath.selectSingleNode( this.mei );
if (score_partwise != null) {
try {
JDOMSource in = new JDOMSource(this.mei);
is = new StreamSource(user.getUrl().substring(0,user.getUrl().lastIndexOf("/")+1)+"mei/musicxml2parttime.xsl");
transformer = transformerFactory.newTransformer(is);
transformer.transform(in, out);
this.mei = out.getDocument();
} catch (Exception q) {
}
}
xpath = XPath.newInstance("/score-timewise");
Element score_timewise = (Element) xpath.selectSingleNode( this.mei );
if (score_timewise != null) {
try {
JDOMSource in = new JDOMSource(this.mei);
is = new StreamSource(user.getUrl().substring(0,user.getUrl().lastIndexOf("/")+1)+"mei/musicxml2mei.xsl");
transformer = transformerFactory.newTransformer(is);
transformer.transform(in, out);
this.mei = out.getDocument();
} catch (Exception q) {
log.debug(q.getLocalizedMessage(),q);
}
}
} catch (Exception e) {
log.debug(e.getLocalizedMessage(),e);
}
finally {
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
}
}
public boolean get (String pid) {
try {
SAXBuilder builder = new SAXBuilder();
this.mei =builder.build(new StringReader(new String(Repository.getDatastream(pid, "MEI_SOURCE",""))));
this.PID = pid;
return true;
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
Common.log(logger,e);
return false;
}
}
public boolean set (String stream) {
try {
SAXBuilder builder = new SAXBuilder();
this.collection="";
this.mei =builder.build(new StringReader(stream));
validate();
this.PID = "";
return true;
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
Common.log(logger,e);
return false;
}
}
public String toString() {
// removeEmpty();
return this.outputter.outputString(this.mei);
}
public String getName() {
try {
return !this.collection.isEmpty() ? this.collection : this.file.getCanonicalPath();
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
return "";
}
}
public String getPID() {
try {
XPath xpath = XPath.newInstance("//m:fileDesc/m:pubStmt//m:identifier[@type='PID']");
xpath.addNamespace( Common.xmlns_mei );
Element idno = (Element) xpath.selectSingleNode( mei );
if (idno != null) {
String s = idno.getTextNormalize();
this.PID = s.startsWith(Common.INFO_FEDORA) ? s.substring(Common.INFO_FEDORA.length()) : s;
} else {
String pid = mei.getRootElement().getAttributeValue("id", Common.xmlns_xml).toLowerCase();
if (pid != null) {
if (!pid.startsWith("o:")) pid= "o:"+pid;
xpath = XPath.newInstance("//m:fileDesc/m:pubStmt");
xpath.addNamespace( Common.xmlns_mei );
Element anchor = (Element) xpath.selectSingleNode( mei );
Element child = new Element ("identifier", Common.xmlns_nmei );
child.setText(Common.INFO_FEDORA+pid);
child.setAttribute("type", "PID");
anchor.addContent(child);
this.PID =pid;
}
}
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
}
return this.PID;
}
public void setPID(String pid) {
try {
XPath xpath = XPath.newInstance("//m:fileDesc/m:pubStmt//m:identifier[@type='PID']");
xpath.addNamespace( Common.xmlns_mei );
Element idno = (Element) xpath.selectSingleNode( mei );
if (idno == null) {
try {
String oid = mei.getRootElement().getAttributeValue("id", Common.xmlns_xml).toLowerCase();
if (oid != null) pid = oid;
if (!pid.startsWith("o:")) pid= "o:"+pid;
} catch (Exception u) {}
xpath = XPath.newInstance("//m:fileDesc/m:pubStmt");
xpath.addNamespace( Common.xmlns_mei );
Element anchor = (Element) xpath.selectSingleNode( mei );
Element child = new Element ("identifier", Common.xmlns_nmei );
child.setText(pid);
child.setAttribute("type", "PID");
anchor.addContent(child);
this.raw = outputter.outputString(this.mei);
} else {
if (this.mode) {
idno.setText(pid);
}
}
this.PID = pid;
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
}
}
public boolean isValid() {
try {
isCustomized = false;
this.raw = null;
XPath xpath = XPath.newInstance( "/m:mei" );
xpath.addNamespace( Common.xmlns_mei );
if ( xpath.selectSingleNode( this.mei ) == null ) {
xpath = XPath.newInstance( "/m:meiCorpus" );
xpath.addNamespace( Common.xmlns_mei );
if ( xpath.selectSingleNode( this.mei ) == null ) return false;
}
String p = props.getProperty("user", "MEI.Customization");
if (p != null && p.equals("1")) {
transform();
isCustomized = true;
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema(new URL(user.getUrl().substring(0,user.getUrl().lastIndexOf("/"))+Common.MEISCHEMA));
Validator validator = schema.newValidator();
try {
validator.validate(new JDOMSource(this.mei));
} catch (Exception q) {
Common.log(logger, "-----------------------\n"+outputter.outputString(this.mei)+"-----------------------\n");
Common.log(logger, q);
isCustomized = true;
return false;
}
}
return true;
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
Common.log(logger, e);
return false;}
}
public boolean transform() {
byte[] stylesheet = null;
try {
try {
stylesheet = Repository.getDatastream("cirilo:"+xuser, "TOMEI" , "");
} catch (Exception ex) {
try {
stylesheet = Repository.getDatastream("cirilo:Backbone", "TOMEI" , "");
} catch (Exception q) {
log.error(q.getLocalizedMessage(),q);
Common.log(logger, q);
return false;
}
}
if (new String(stylesheet).contains(":template")) {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new StringReader(new String(stylesheet, "UTF-8"))));
JDOMSource in = new JDOMSource(this.mei);
JDOMResult out = new JDOMResult();
transformer.transform(in, out);
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
SAXBuilder builder = new SAXBuilder();
this.mei = builder.build( new StringReader( outputter.outputString(out.getResult())) );
}
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
Common.log(logger, e);
}
return true;
}
public boolean write(boolean mode) {
try {
if (!onlyValidate) {
if (this.collection.isEmpty()) {
if (mode || (!isCustomized && this.raw !=null && this.file.toString().contains(".xml"))) {
FileOutputStream fos = new FileOutputStream( this.file.toString() );
BufferedWriter out = new BufferedWriter(new OutputStreamWriter( fos, "UTF-8" ) );
if (mode) out.write(new String(outputter.outputString(this.mei).getBytes("UTF-8"),"UTF-8"));
else if (!isCustomized && this.raw !=null) out.write(this.raw);
out.close();
}
} else {
if (mode || (!isCustomized && this.raw !=null && this.file.toString().contains(".xml"))) {
eXist eX = new eXist (this.collection);
org.xmldb.api.base.Collection coll = DatabaseManager.getCollection( URI + eX.getCollection(), user.getExistUser(), user.getExistPasswd() );
XMLResource res = (XMLResource) coll.getResource(eX.getStream());
if (mode) res.setContent(new String(outputter.outputString(this.mei).getBytes("UTF-8"),"UTF-8"));
else if (!isCustomized && this.raw !=null) res.setContent(this.raw);
coll.storeResource(res);
coll.close();
}
}
}
return true;
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
return false;
}
}
public void createRELS_INT(String pid)
{
String currPID = this.PID;
this.PID = pid != null ? pid :this.PID;
String rdfs = null;
try {
try {
byte[] url0 = Repository.getDatastream(pid != null ? pid : this.PID, "TORDF" , "");
URLConnection con = new URL (new String(url0)).openConnection();
con.setUseCaches(false);
Document doc = builder.build(con.getInputStream());
rdfs = outputter.outputString(doc);
} catch (Exception ex0) {
try {
Document doc = builder.build(new StringReader(new String(Repository.getDatastream("cirilo:"+xuser, "TORDF",""))));
rdfs = outputter.outputString(doc);
} catch (Exception ex1) {
Document doc = builder.build(new StringReader(new String(Repository.getDatastream("cirilo:Backbone", "TORDF",""))));
rdfs = outputter.outputString(doc);
}
}
try {
if (rdfs!= null && rdfs.contains("xsl:template")) {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new StringReader(rdfs)));
JDOMSource in = new JDOMSource(this.mei);
JDOMResult out = new JDOMResult();
transformer.transform(in, out);
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
File temp = File.createTempFile("tmp","xml");
FileOutputStream fos = new FileOutputStream(temp);
fos.write( outputter.outputString(out.getResult()).getBytes("UTF-8") );
fos.close();
TripleStoreFactory tf = new TripleStoreFactory();
if (tf.getStatus()) {
tf.update(temp, this.PID);
}
tf.close();
if (!Repository.exists(this.PID, "RDF")) {
Repository.addDatastream(this.PID, "RDF", "RDF Stream created by TORDF", "M", "text/xml", temp);
} else {
Repository.modifyDatastream(this.PID, "RDF", "text/xml", "M", temp);
}
temp.delete();
}
} catch (Exception q) {
log.error(q.getLocalizedMessage(),q);
Common.log(logger, q);
}
} catch (Exception e) {
try {
log.error(e.getLocalizedMessage(),e);
Common.log(logger, e);
} catch (Exception q) {}
} finally {
this.PID =currPID;
}
}
public void createMapping(String pid, CDefaultGuiAdapter moGA)
{
try {
if (!onlyValidate) {
byte[] url = Repository.getDatastream(pid != null ? pid : this.PID, "DC_MAPPING" , "");
SAXBuilder builder = new SAXBuilder();
URLConnection con = new URL (new String(url)).openConnection();
con.setUseCaches(false);
Document mapping = builder.build(con.getInputStream());
MDMapper m = new MDMapper(this.PID,outputter.outputString(mapping));
org.jdom.Document dc = builder.build( new StringReader (m.transform(this.mei) ) );
if (moGA != null) {
Element root = dc.getRootElement();
for (int i = 1; i < org.emile.cirilo.Common.DCMI.length; i++) {
String s = (String) moGA.getText("jtf"+ org.emile.cirilo.Common.DCMI[i]);
if (s.length() > 0) {
StringTokenizer st = new StringTokenizer(s, "~");
if (st.hasMoreTokens()) {
while (st.hasMoreTokens()) {
String p = Common.itrim(st.nextToken());
Element e = new Element(
org.emile.cirilo.Common.DCMI[i].toLowerCase(),
org.emile.cirilo.Common.xmlns_dc);
e.addContent(p);
root.addContent(e);
}
}
}
}
}
dc = Common.validate(dc);
Repository.modifyDatastreamByValue(this.PID, "DC", "text/xml", outputter.outputString(dc));
}
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
Common.log(logger,e);
}
finally {
}
}
public void validate(String pid, CDefaultGuiAdapter moGA)
{
try {
String p;
if(this.PID != null && this.PID.startsWith("cirilo:")) return;
p = props.getProperty("user", "MEI.DCMapping");
if (p == null || p.equals("1")) createMapping(pid, moGA);
p = props.getProperty("user", "MEI.SEMExtraction");
if (p == null || p.equals("1")) createRELS_INT(null);
p = props.getProperty("user", "MEI.RefreshSource");
write(p != null && p.equals("1"));
} catch (Exception e) {
log.error(e.getLocalizedMessage(),e);
}
}
}