/*
* Licensed to the Ant-Contrib Project under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The Ant-Contrib licenses this file to You 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.
*/
package net.sf.antcontrib.cpptasks.apple;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* Static class that provides methods to serialize
* a Map to a Cocoa XML Property List. Does not currently support
* date or data elements.
*/
public final class PropertyListSerialization {
/**
* Private constructor.
*/
private PropertyListSerialization() {
}
/**
* Serializes a property list into a Cocoa XML Property List document.
* @param propertyList property list.
* @param file destination.
* @param comments comments to insert into document.
* @throws SAXException if exception during serialization.
* @throws TransformerConfigurationException if exception creating serializer.
*/
public static void serialize(final Map propertyList,
final List comments,
final File file)
throws IOException, SAXException,
TransformerConfigurationException {
SAXTransformerFactory sf = (SAXTransformerFactory)
SAXTransformerFactory.newInstance();
TransformerHandler handler = sf.newTransformerHandler();
FileOutputStream os = new FileOutputStream(file);
StreamResult result = new StreamResult(os);
handler.setResult(result);
handler.startDocument();
for(Iterator iter = comments.iterator(); iter.hasNext();) {
char[] comment = String.valueOf(iter.next()).toCharArray();
handler.comment(comment, 0, comment.length);
}
AttributesImpl attributes = new AttributesImpl();
handler.startElement(null, "plist", "plist", attributes);
serializeMap(propertyList, handler);
handler.endElement(null, "plist", "plist");
handler.endDocument();
}
/**
* Serialize a map as a dict element.
* @param map map to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeMap(final Map map,
final ContentHandler handler)
throws SAXException {
AttributesImpl attributes = new AttributesImpl();
handler.startElement(null, "dict", "dict", attributes);
if (map.size() > 0) {
//
// need to output with sorted keys to maintain
// reproducability
//
Object[] keys = map.keySet().toArray();
Arrays.sort(keys);
for(int i = 0; i < keys.length; i++) {
String key = String.valueOf(keys[i]);
handler.startElement(null, "key", "key", attributes);
handler.characters(key.toCharArray(), 0, key.length());
handler.endElement(null, "key", "key");
serializeObject(map.get(keys[i]), handler);
}
}
handler.endElement(null, "dict", "dict");
}
/**
* Serialize a list as an array element.
* @param list list to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeList(final List list,
final ContentHandler handler)
throws SAXException {
AttributesImpl attributes = new AttributesImpl();
handler.startElement(null, "array", "array", attributes);
for(Iterator iter = list.iterator();iter.hasNext();) {
serializeObject(iter.next(), handler);
}
handler.endElement(null, "array", "array");
}
/**
* Creates an element with the specified tag name and character content.
* @param tag tag name.
* @param content character content.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeElement(final String tag,
final String content,
final ContentHandler handler)
throws SAXException {
AttributesImpl attributes = new AttributesImpl();
handler.startElement(null, tag, tag, attributes);
handler.characters(content.toCharArray(), 0, content.length());
handler.endElement(null, tag, tag);
}
/**
* Serialize a Number as an integer element.
* @param integer number to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeInteger(final Number integer,
final ContentHandler handler)
throws SAXException {
serializeElement("integer", String.valueOf(integer.longValue()),
handler);
}
/**
* Serialize a Number as a real element.
* @param real number to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeReal(final Number real,
final ContentHandler handler)
throws SAXException {
serializeElement("real",
String.valueOf(real.doubleValue()),
handler);
}
/**
* Serialize a Boolean as a true or false element.
* @param val boolean to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeBoolean(final Boolean val,
final ContentHandler handler)
throws SAXException {
String tag = "false";
if (val.booleanValue()) {
tag = "true";
}
AttributesImpl attributes = new AttributesImpl();
handler.startElement(null, tag, tag, attributes);
handler.endElement(null, tag, tag);
}
/**
* Serialize a string as a string element.
* @param val string to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeString(final String val,
final ContentHandler handler)
throws SAXException {
serializeElement("string",
val,
handler);
}
/**
* Serialize an object using the best available element.
* @param obj object to serialize.
* @param handler destination of serialization events.
* @throws SAXException if exception during serialization.
*/
private static void serializeObject(final Object obj,
final ContentHandler handler)
throws SAXException {
if (obj instanceof Map) {
serializeMap((Map) obj, handler);
} else if (obj instanceof List) {
serializeList((List) obj, handler);
} else if (obj instanceof Number) {
if(obj instanceof Double
||obj instanceof Float) {
serializeReal((Number) obj, handler);
} else {
serializeInteger((Number) obj, handler);
}
} else if (obj instanceof Boolean) {
serializeBoolean((Boolean) obj, handler);
} else {
serializeString(String.valueOf(obj), handler);
}
}
}