package com.cloudhopper.sxmp;
/*
* #%L
* ch-sxmp
* %%
* Copyright (C) 2012 - 2013 Cloudhopper by Twitter
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.cloudhopper.commons.util.HexUtil;
import com.cloudhopper.commons.util.StringUtil;
import com.cloudhopper.sxmp.util.XmlEscapeUtil;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import org.apache.commons.lang.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
/**
*
* @author joelauer
*/
public class SxmpWriter {
static private void writeXmlHeader(Writer out, Operation operation) throws IOException {
// v1.1 needs to be UTF-8; v1.0 was unspecified
if (operation.getVersion().equals(SxmpParser.VERSION_1_0))
out.write("<?xml version=\"1.0\"?>\n");
else
out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
}
static private void writeOperationStartTag(Writer out, Operation.Type type) throws IOException {
if (type == null) {
throw new NullPointerException("Operation type cannot be null");
}
out.write("<operation type=\"" + type.getValue() + "\">\n");
}
static private void writeOperationEndTag(Writer out) throws IOException {
out.write("</operation>\n");
}
static private void writeRequestResponseTag(Writer out, Operation operation) throws IOException {
out.write(operation.getType().getValue());
if (operation.isRequest()) {
out.write("Request");
} else {
out.write("Response");
}
}
static private void writeRequestResponseStartTag(Writer out, Operation operation) throws IOException {
out.write(" <");
writeRequestResponseTag(out, operation);
if (operation.getReferenceId() != null) {
out.write(" referenceId=\"");
out.write(operation.getReferenceId());
out.write("\"");
}
out.write(">\n");
}
static private void writeRequestResponseEndTag(Writer out, Operation operation) throws IOException {
out.write(" </");
writeRequestResponseTag(out, operation);
out.write(">\n");
}
static private void writeErrorElement(Writer out, Response response) throws IOException {
out.write(" <error code=\"");
out.write(response.getErrorCode().toString());
out.write("\" message=\"");
out.write(StringUtil.escapeXml(response.getErrorMessage()));
out.write("\"/>\n");
}
/**
static public byte[] createByteArray(Operation operation) throws SxmpErrorException, IOException {
// most requests will be ~1000 bytes
//FastByteArrayOutputStream baos = new FastByteArrayOutputStream(1000);
ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
OutputStreamWriter out = new OutputStreamWriter(baos, "ISO-8859-1");
SxmpWriter.write(out, operation);
byte[] data = baos.toByteArray();
//out.close();
//baos.close();
return data;
}
*/
static public String createString(Operation operation) throws SxmpErrorException, IOException {
StringWriter sw = new StringWriter(1000);
SxmpWriter.write(sw, operation);
return sw.toString();
}
static public void write(Writer out, Operation operation) throws SxmpErrorException, IOException {
write(out, operation, true);
}
static public void write(Writer out, Operation operation, boolean withXmlHeader) throws SxmpErrorException, IOException {
if (withXmlHeader) writeXmlHeader(out, operation);
writeOperationStartTag(out, operation.getType());
// let's validate this operation is valid
operation.validate();
if (operation instanceof ErrorResponse) {
// write out just an ErrorResponse
writeErrorElement(out, (ErrorResponse)operation);
} else if (operation instanceof Request) {
// any request requires an account to be printed out
Request request = (Request)operation;
if (request.getAccount() != null) {
out.write(" <account username=\"");
out.write(StringUtil.escapeXml(request.getAccount().getUsername()));
out.write("\" password=\"");
out.write(StringUtil.escapeXml(request.getAccount().getPassword()));
out.write("\"/>\n");
}
if (request.getApplication() != null) {
out.write(" <application>");
out.write(StringUtil.escapeXml(request.getApplication().getName()));
out.write("</application>\n");
}
writeRequestResponseStartTag(out, operation);
// tickets are now supported any any request
if (request.getTicketId() != null) {
out.write(" <ticketId>");
out.write(StringUtil.escapeXml(request.getTicketId()));
out.write("</ticketId>\n");
}
if (operation instanceof DeliveryReportRequest) {
DeliveryReportRequest deliveryRequest = (DeliveryReportRequest)operation;
if (deliveryRequest.getStatus() != null) {
out.write(" <status code=\"");
out.write(deliveryRequest.getStatus().getCode().toString());
out.write("\" message=\"");
out.write(StringUtil.escapeXml(deliveryRequest.getStatus().getMessage()));
out.write("\"/>\n");
}
if (deliveryRequest.getMessageErrorCode() != null) {
out.write(" <messageError code=\"");
out.write(deliveryRequest.getMessageErrorCode().toString());
out.write("\"/>\n");
}
if (deliveryRequest.getCreateDate() != null) {
out.write(" <createDate>");
out.write(SxmpParser.dateTimeFormat.print(deliveryRequest.getCreateDate()));
out.write("</createDate>\n");
}
if (deliveryRequest.getFinalDate() != null) {
out.write(" <finalDate>");
out.write(SxmpParser.dateTimeFormat.print(deliveryRequest.getFinalDate()));
out.write("</finalDate>\n");
}
} else if (operation instanceof MessageRequest) {
MessageRequest messageRequest = (MessageRequest)operation;
if (messageRequest.getOperatorId() != null) {
out.write(" <operatorId>");
out.write(messageRequest.getOperatorId().toString());
out.write("</operatorId>\n");
}
if (messageRequest.getPriority() != null) {
out.write(" <priority>");
out.write(messageRequest.getPriority().getPriorityFlag().toString());
out.write("</priority>\n");
}
if (operation instanceof SubmitRequest) {
SubmitRequest submitRequest = (SubmitRequest)operation;
if (submitRequest.getDeliveryReport() != null) {
out.write(" <deliveryReport>");
out.write(submitRequest.getDeliveryReport().toString().toLowerCase());
out.write("</deliveryReport>\n");
}
}
if (messageRequest.getSourceAddress() != null) {
out.write(" <sourceAddress type=\"");
out.write(messageRequest.getSourceAddress().getType().toString().toLowerCase());
out.write("\">");
out.write(messageRequest.getSourceAddress().getAddress());
out.write("</sourceAddress>\n");
}
if (messageRequest.getDestinationAddress() != null) {
out.write(" <destinationAddress type=\"");
out.write(messageRequest.getDestinationAddress().getType().toString().toLowerCase());
out.write("\">");
// push dest address is not guaranteed to be XML-safe
// do minimum-necessary escaping? or better to stay standardized & escape everything?
if (messageRequest.getDestinationAddress().getType() == MobileAddress.Type.PUSH_DESTINATION) {
out.write(XmlEscapeUtil.escapeTextXml(messageRequest.getDestinationAddress().getAddress()));
} else {
out.write(messageRequest.getDestinationAddress().getAddress());
}
out.write("</destinationAddress>\n");
}
if (messageRequest.getText() != null) {
String charset = messageRequest.getTextEncoding().getCharset();
out.write(" <text encoding=\"");
out.write(charset);
out.write("\">");
out.write(HexUtil.toHexString(messageRequest.getText().getBytes(charset)));
out.write("</text>\n");
}
// this is a v1.1 option; only write if version == 1.1
if (messageRequest.getOptionalParams() != null &&
messageRequest.getVersion().equals(SxmpParser.VERSION_1_1)) {
//String charset = messageRequest.getTextEncoding().getCharset();
out.write(" <optionalParams>");
JSONObject jsonObj = new JSONObject(messageRequest.getOptionalParams());
// JSON encoding is not XML-safe
// do minimum-necessary escaping? or better to stay standardized & escape everything?
// tradeoff: all " and ' become " and ' and all json strings are quoted.
out.write(XmlEscapeUtil.escapeTextXml(jsonObj.toString()));
out.write("</optionalParams>\n");
}
}
writeRequestResponseEndTag(out, operation);
} else {
writeRequestResponseStartTag(out, operation);
writeErrorElement(out, (Response)operation);
// tickets on responses are now supported for submits or delivers
if (operation instanceof SubmitResponse || operation instanceof DeliverResponse) {
if (operation.getTicketId() != null) {
out.write(" <ticketId>");
out.write(StringUtil.escapeXml(operation.getTicketId()));
out.write("</ticketId>\n");
}
}
writeRequestResponseEndTag(out, operation);
}
writeOperationEndTag(out);
}
}