package org.develnext.jphp.ext.xml.classes;
import org.develnext.jphp.ext.xml.XmlExtension;
import org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import php.runtime.Memory;
import php.runtime.annotation.Reflection.Name;
import php.runtime.annotation.Reflection.Nullable;
import php.runtime.annotation.Reflection.Signature;
import php.runtime.env.Environment;
import php.runtime.ext.core.classes.format.WrapProcessor;
import php.runtime.ext.core.classes.stream.Stream;
import php.runtime.ext.java.JavaException;
import php.runtime.invoke.Invoker;
import php.runtime.memory.ObjectMemory;
import php.runtime.memory.StringMemory;
import php.runtime.reflection.ClassEntity;
import php.runtime.reflection.support.ReflectionUtils;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
@Name(XmlExtension.NAMESPACE + "XmlProcessor")
public class WrapXmlProcessor extends WrapProcessor {
protected DocumentBuilderFactory builderFactory;
protected DocumentBuilder builder;
protected TransformerFactory transformerFactory;
protected Transformer transformer;
protected Invoker onWarning;
protected Invoker onError;
protected Invoker onFatalError;
public WrapXmlProcessor(Environment env, ClassEntity clazz) {
super(env, clazz);
}
@Signature
public void __construct(final Environment env) throws ParserConfigurationException, TransformerConfigurationException {
transformerFactory = TransformerFactory.newInstance();
transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
builderFactory = DocumentBuilderFactory.newInstance();
builder = builderFactory.newDocumentBuilder();
builder.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
if (onWarning != null) {
onWarning.callAny(new JavaException(env, exception));
}
}
@Override
public void error(SAXParseException exception) throws SAXException {
if (onError != null) {
onError.callAny(new JavaException(env, exception));
}
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
if (onFatalError != null) {
onFatalError.callAny(new JavaException(env, exception));
} else {
throw exception;
}
}
});
}
@Override
@Signature
public Memory parse(Environment environment, Memory... args) {
if (onWarning != null) onWarning.setTrace(environment.trace());
if (onError != null) onError.setTrace(environment.trace());
if (onFatalError != null) onFatalError.setTrace(environment.trace());
InputStream stream = null;
try {
if (args[0].instanceOf(Stream.class)) {
stream = Stream.getInputStream(environment, args[0]);
} else {
stream = new ByteArrayInputStream(args[0].getBinaryBytes(environment.getDefaultCharset()));
}
Document document = builder.parse(stream);
return new ObjectMemory(new WrapDomDocument(environment, document));
} catch (SAXException | IOException e) {
environment.exception(ProcessorException.class, e.getMessage());
return Memory.NULL;
} finally {
if (stream != null) Stream.closeStream(environment, stream);
}
}
@Override
@Signature
public Memory format(Environment environment, Memory... args) {
if (!args[0].instanceOf(WrapDomDocument.class)) {
throw new IllegalArgumentException(
"Argument #1 must be instance of " + ReflectionUtils.getClassName(WrapDomDocument.class)
);
}
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
try {
transformer.transform(new DOMSource(args[0].toObject(WrapDomDocument.class).getWrappedObject()), result);
return StringMemory.valueOf(writer.toString());
} catch (TransformerException e) {
environment.exception(ProcessorException.class, e.getMessage());
return Memory.NULL;
}
}
@Override
@Signature
public Memory formatTo(Environment environment, Memory... args) {
if (!args[0].instanceOf(WrapDomDocument.class)) {
throw new IllegalArgumentException(
"Argument #1 must be instance of " + ReflectionUtils.getClassName(WrapDomDocument.class)
);
}
OutputStream output = Stream.getOutputStream(environment, args[1]);
StreamResult result = new StreamResult(output);
try {
transformer.transform(new DOMSource(args[0].toObject(WrapDomDocument.class).getWrappedObject()), result);
} catch (TransformerException e) {
environment.exception(ProcessorException.class, e.getMessage());
return Memory.NULL;
} finally {
Stream.closeStream(environment, output);
}
return Memory.NULL;
}
@Signature
public Document createDocument() {
return builder.newDocument();
}
@Signature
public void onWarning(@Nullable Invoker invoker) {
onWarning = invoker;
}
@Signature
public void onError(@Nullable Invoker invoker) {
onError = invoker;
}
@Signature
public void onFatalError(@Nullable Invoker invoker) {
onFatalError = invoker;
}
}