Updated batch support following comments from Debajit
diff --git a/src/com/google/wireless/gdata/data/XmlUtils.java b/src/com/google/wireless/gdata/data/XmlUtils.java
index 1c067d3..d838372 100644
--- a/src/com/google/wireless/gdata/data/XmlUtils.java
+++ b/src/com/google/wireless/gdata/data/XmlUtils.java
@@ -77,6 +77,30 @@
+ "depth " + parentDepth);
}
+ /**
+ * Supply a 'skipSubTree' API which, for some reason, the kxml2 pull parser
+ * hasn't implemented.
+ */
+ public void skipSubTree(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ // Iterate the remaining structure for this element, discarding events
+ // until we hit the element's corresponding end tag.
+ int level = 1;
+ while (level > 0) {
+ int eventType = parser.next();
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ ++level;
+ break;
+ case XmlPullParser.END_TAG:
+ --level;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
// public static void parseChildrenToSerializer(XmlPullParser parser, XmlSerializer serializer)
// throws XmlPullParserException, IOException {
// int parentDepth = parser.getDepth();
diff --git a/src/com/google/wireless/gdata2/client/GDataClient.java b/src/com/google/wireless/gdata2/client/GDataClient.java
index ef3d108..90a3a2b 100644
--- a/src/com/google/wireless/gdata2/client/GDataClient.java
+++ b/src/com/google/wireless/gdata2/client/GDataClient.java
@@ -164,4 +164,23 @@
public InputStream updateMediaEntry(String editUri, String authToken, String eTag,
InputStream mediaEntryInputStream, String contentType)
throws HttpException, IOException;
+
+ /**
+ * Connects to a GData server (specified by the batchUrl) and submits a
+ * batch for processing. The response from the server is returned as an
+ * {@link InputStream}. The caller is responsible for calling
+ * {@link InputStream#close()} on the returned {@link InputStream}.
+ *
+ * @param batchUrl The batch url to which the batch is submitted.
+ * @param authToken the authentication token that should be used when
+ * submitting the batch.
+ * @param batch The batch of entries to submit.
+ * @throws IOException Thrown if an io error occurs while communicating with
+ * the service.
+ * @throws HttpException if the service returns an error response.
+ */
+ InputStream submitBatch(String batchUrl,
+ String authToken,
+ GDataSerializer batch)
+ throws HttpException, IOException;
}
diff --git a/src/com/google/wireless/gdata2/client/GDataParserFactory.java b/src/com/google/wireless/gdata2/client/GDataParserFactory.java
index 56546fe..f08b384 100644
--- a/src/com/google/wireless/gdata2/client/GDataParserFactory.java
+++ b/src/com/google/wireless/gdata2/client/GDataParserFactory.java
@@ -8,6 +8,7 @@
import com.google.wireless.gdata2.serializer.GDataSerializer;
import java.io.InputStream;
+import java.util.Enumeration;
/**
* Factory that creates {@link GDataParser}s and {@link GDataSerializer}s.
@@ -45,4 +46,12 @@
* @return The GDataSerializer that will serialize entry.
*/
GDataSerializer createSerializer(Entry entry);
+
+ /**
+ * Creates a new {@link GDataSerializer} for the provided batch of entries.
+ *
+ * @param batch An enumeration of entries comprising the batch.
+ * @return The GDataSerializer that will serialize the batch.
+ */
+ GDataSerializer createSerializer(Enumeration batch);
}
diff --git a/src/com/google/wireless/gdata2/client/GDataServiceClient.java b/src/com/google/wireless/gdata2/client/GDataServiceClient.java
index ca12df3..e39f580 100644
--- a/src/com/google/wireless/gdata2/client/GDataServiceClient.java
+++ b/src/com/google/wireless/gdata2/client/GDataServiceClient.java
@@ -11,6 +11,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.util.Enumeration;
/**
* Abstract base class for service-specific clients to access GData feeds.
@@ -217,4 +218,23 @@
}
}
}
+
+ /**
+ * Submits a batch of operations.
+ * @param feedEntryClass the type of the entry to expect.
+ * @param batchUrl The url to which the batch is submitted.
+ * @param authToken The authentication token for this user.
+ * @param entries an enumeration of the entries to submit.
+ * @throws HttpException if the service returns an error response
+ * @throws ParseException Thrown if the server response cannot be parsed.
+ * @throws IOException Thrown if an error occurs while communicating with the
+ * GData service.
+ */
+ public GDataParser submitBatch(Class feedEntryClass, String batchUrl, String authToken,
+ Enumeration entries) throws ParseException, IOException, HttpException {
+ GDataSerializer serializer = gDataParserFactory.createSerializer(entries);
+ InputStream is = gDataClient.submitBatch(batchUrl, authToken, serializer);
+ return gDataParserFactory.createParser(feedEntryClass, is);
+ }
+
}
diff --git a/src/com/google/wireless/gdata2/contacts/parser/xml/XmlContactsGDataParserFactory.java b/src/com/google/wireless/gdata2/contacts/parser/xml/XmlContactsGDataParserFactory.java
index 2eb3209..9b13d8d 100644
--- a/src/com/google/wireless/gdata2/contacts/parser/xml/XmlContactsGDataParserFactory.java
+++ b/src/com/google/wireless/gdata2/contacts/parser/xml/XmlContactsGDataParserFactory.java
@@ -14,11 +14,13 @@
import com.google.wireless.gdata2.parser.xml.XmlParserFactory;
import com.google.wireless.gdata2.parser.xml.XmlMediaEntryGDataParser;
import com.google.wireless.gdata2.serializer.GDataSerializer;
+import com.google.wireless.gdata2.serializer.xml.XmlBatchGDataSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.InputStream;
+import java.util.Enumeration;
/**
* GDataParserFactory that creates XML GDataParsers and GDataSerializers for
@@ -122,4 +124,14 @@
}
throw new IllegalArgumentException("unexpected entry type, " + entry.getClass().toString());
}
+
+ /**
+ * Creates a new {@link GDataSerializer} for the given batch.
+ *
+ * @param batch the {@link Enumeration} of entries in the batch.
+ * @return The {@link GDataSerializer} tha will serialize this batch.
+ */
+ public GDataSerializer createSerializer(Enumeration batch) {
+ return new XmlBatchGDataSerializer(this, xmlFactory, batch);
+ }
}
diff --git a/src/com/google/wireless/gdata2/contacts/serializer/xml/XmlContactEntryGDataSerializer.java b/src/com/google/wireless/gdata2/contacts/serializer/xml/XmlContactEntryGDataSerializer.java
index 1b8392c..4646490 100644
--- a/src/com/google/wireless/gdata2/contacts/serializer/xml/XmlContactEntryGDataSerializer.java
+++ b/src/com/google/wireless/gdata2/contacts/serializer/xml/XmlContactEntryGDataSerializer.java
@@ -33,7 +33,6 @@
super(factory, entry);
}
- @Override
protected void declareExtraEntryNamespaces(XmlSerializer serializer) throws IOException {
super.declareExtraEntryNamespaces(serializer);
serializer.setPrefix(XmlContactsGDataParser.NAMESPACE_CONTACTS,
diff --git a/src/com/google/wireless/gdata2/data/Entry.java b/src/com/google/wireless/gdata2/data/Entry.java
index fff706e..f0fbf03 100644
--- a/src/com/google/wireless/gdata2/data/Entry.java
+++ b/src/com/google/wireless/gdata2/data/Entry.java
@@ -2,6 +2,7 @@
package com.google.wireless.gdata2.data;
+import com.google.wireless.gdata2.data.batch.BatchInfo;
import com.google.wireless.gdata2.parser.ParseException;
/**
@@ -26,6 +27,7 @@
private String updateDate = null;
private String eTagValue = null;
private boolean deleted = false;
+ private BatchInfo batchInfo = null;
/**
* Creates a new empty entry.
@@ -50,6 +52,7 @@
publicationDate = null;
updateDate = null;
deleted = false;
+ batchInfo = null;
}
/**
@@ -235,7 +238,23 @@
public void setETag(String eTag) {
eTagValue = eTag;
}
-
+
+ /**
+ * Used internally to access batch related properties.
+ * Clients should use {@link BatchUtils} instead.
+ */
+ public BatchInfo getBatchInfo() {
+ return batchInfo;
+ }
+
+ /**
+ * Used internally to update batch related properties.
+ * Clients should use {@link BatchUtils} instead.
+ */
+ public void setBatchInfo(BatchInfo batchInfo) {
+ this.batchInfo = batchInfo;
+ }
+
/**
* Appends the name and value to this StringBuffer, if value is not null.
* Uses the format: "<NAME>: <VALUE>\n"
@@ -274,6 +293,10 @@
appendIfNotNull(sb, "PUBLICATION DATE", publicationDate);
appendIfNotNull(sb, "UPDATE DATE", updateDate);
appendIfNotNull(sb, "DELETED", String.valueOf(deleted));
+ appendIfNotNull(sb, "ETAG", String.valueOf(eTagValue));
+ if (batchInfo != null) {
+ appendIfNotNull(sb, "BATCH", batchInfo.toString());
+ }
}
/**
diff --git a/src/com/google/wireless/gdata2/data/batch/BatchInfo.java b/src/com/google/wireless/gdata2/data/batch/BatchInfo.java
new file mode 100644
index 0000000..ef461d2
--- /dev/null
+++ b/src/com/google/wireless/gdata2/data/batch/BatchInfo.java
@@ -0,0 +1,30 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package com.google.wireless.gdata2.data.batch;
+
+/**
+ * Opaque container for batch related info associated with an entry.
+ * Clients should use {@link BatchUtils} to access this data instead.
+ */
+public class BatchInfo {
+ String id;
+ String operation;
+ BatchStatus status;
+ BatchInterrupted interrupted;
+
+ /* package */ BatchInfo() {
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("id: ").append(id);
+ sb.append(" op: ").append(operation);
+ if (status != null) {
+ sb.append(" sc: ").append(status.getStatusCode());
+ }
+ if (interrupted != null) {
+ sb.append(" interrupted: ").append(interrupted.getReason());
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/com/google/wireless/gdata2/data/batch/BatchInterrupted.java b/src/com/google/wireless/gdata2/data/batch/BatchInterrupted.java
new file mode 100644
index 0000000..ff8a69f
--- /dev/null
+++ b/src/com/google/wireless/gdata2/data/batch/BatchInterrupted.java
@@ -0,0 +1,75 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package com.google.wireless.gdata2.data.batch;
+
+/**
+ * Holds status information about a batch that was interrupted.
+ */
+public class BatchInterrupted {
+ private String reason;
+ private int total;
+ private int success;
+ private int error;
+
+ /**
+ * Creates a new empty BatchInterrupted.
+ */
+ public BatchInterrupted() {
+ }
+
+ /**
+ * Returns the reason for this failure.
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * Sets the reason for this failure.
+ */
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ /**
+ * Gets the total number of entries read.
+ */
+ public int getTotalCount() {
+ return total;
+ }
+
+ /**
+ * Sets the number of entries read.
+ */
+ public void setTotalCount(int total) {
+ this.total = total;
+ }
+
+ /**
+ * Gets the number of entries that were processed successfully.
+ */
+ public int getSuccessCount() {
+ return success;
+ }
+
+ /**
+ * Sets the number of entries successfuly processed.
+ */
+ public void setSuccessCount(int success) {
+ this.success = success;
+ }
+
+ /**
+ * Gets the number of entries that were rejected.
+ */
+ public int getErrorCount() {
+ return error;
+ }
+
+ /**
+ * Sets the number of entries that failed.
+ */
+ public void setErrorCount(int error) {
+ this.error = error;
+ }
+}
diff --git a/src/com/google/wireless/gdata2/data/batch/BatchStatus.java b/src/com/google/wireless/gdata2/data/batch/BatchStatus.java
new file mode 100644
index 0000000..7a19afd
--- /dev/null
+++ b/src/com/google/wireless/gdata2/data/batch/BatchStatus.java
@@ -0,0 +1,75 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package com.google.wireless.gdata2.data.batch;
+
+/**
+ * Holds result status for an individual batch operation.
+ */
+public class BatchStatus {
+ private int statusCode;
+ private String reason;
+ private String contentType;
+ private String content;
+
+ /**
+ * Creates a new empty BatchStatus.
+ */
+ public BatchStatus() {
+ }
+
+ /**
+ * Returns the status of this operation.
+ */
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ /**
+ * Sets the status of this operation.
+ */
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ /**
+ * Returns the reason for this status.
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * Sets the reason for this status.
+ */
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ /**
+ * Returns the content type of the response.
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ /**
+ * Sets the content type of the response.
+ */
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Returns the response content, if any.
+ */
+ public String getContent() {
+ return content;
+ }
+
+ /**
+ * Sets the response content.
+ */
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
diff --git a/src/com/google/wireless/gdata2/data/batch/BatchUtils.java b/src/com/google/wireless/gdata2/data/batch/BatchUtils.java
new file mode 100644
index 0000000..c237601
--- /dev/null
+++ b/src/com/google/wireless/gdata2/data/batch/BatchUtils.java
@@ -0,0 +1,93 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package com.google.wireless.gdata2.data.batch;
+
+import com.google.wireless.gdata2.data.Entry;
+
+/**
+ * Utility methods for dealing with batch operations.
+ */
+public class BatchUtils {
+
+ public static final String OPERATION_INSERT = "insert";
+
+ public static final String OPERATION_UPDATE = "update";
+
+ public static final String OPERATION_QUERY = "query";
+
+ public static final String OPERATION_DELETE = "delete";
+
+ private BatchUtils() {
+ }
+
+ /**
+ * Returns the batch id of the given entry, or null if none.
+ */
+ public static String getBatchId(Entry entry) {
+ BatchInfo info = entry.getBatchInfo();
+ return info == null ? null : info.id;
+ }
+
+ /**
+ * Sets the batch id of the given entry.
+ */
+ public static void setBatchId(Entry entry, String id) {
+ getOrCreateBatchInfo(entry).id = id;
+ }
+
+ /**
+ * Returns the batch operation of the given entry.
+ */
+ public static String getBatchOperation(Entry entry) {
+ BatchInfo info = entry.getBatchInfo();
+ return info == null ? null : info.operation;
+ }
+
+ /**
+ * Sets the operation for the given batch entry.
+ */
+ public static void setBatchOperation(Entry entry, String operation) {
+ getOrCreateBatchInfo(entry).operation = operation;
+ }
+
+ /**
+ * Returns the status of the given batch entry.
+ */
+ public static BatchStatus getBatchStatus(Entry entry) {
+ BatchInfo info = entry.getBatchInfo();
+ return info == null ? null : info.status;
+ }
+
+ /**
+ * Sets the status of the given batch entry.
+ */
+ public static void setBatchStatus(Entry entry, BatchStatus status) {
+ getOrCreateBatchInfo(entry).status = status;
+ }
+
+ /**
+ * Returns the interrupted status of the given entry, or null if none.
+ */
+ public static BatchInterrupted getBatchInterrupted(Entry entry) {
+ BatchInfo info = entry.getBatchInfo();
+ return info == null ? null : info.interrupted;
+ }
+
+ /**
+ * Sets the interrupted status of the given entry.
+ */
+ public static void setBatchInterrupted(Entry entry,
+ BatchInterrupted interrupted) {
+ getOrCreateBatchInfo(entry).interrupted = interrupted;
+ }
+
+ private static BatchInfo getOrCreateBatchInfo(Entry entry) {
+ BatchInfo info = entry.getBatchInfo();
+ if (info == null) {
+ info = new BatchInfo();
+ entry.setBatchInfo(info);
+ }
+ return info;
+ }
+
+}
diff --git a/src/com/google/wireless/gdata2/parser/xml/XmlGDataParser.java b/src/com/google/wireless/gdata2/parser/xml/XmlGDataParser.java
index 44fd2a2..149882d 100644
--- a/src/com/google/wireless/gdata2/parser/xml/XmlGDataParser.java
+++ b/src/com/google/wireless/gdata2/parser/xml/XmlGDataParser.java
@@ -8,6 +8,9 @@
import com.google.wireless.gdata2.data.XmlUtils;
import com.google.wireless.gdata2.parser.GDataParser;
import com.google.wireless.gdata2.parser.ParseException;
+import com.google.wireless.gdata2.data.batch.BatchInterrupted;
+import com.google.wireless.gdata2.data.batch.BatchStatus;
+import com.google.wireless.gdata2.data.batch.BatchUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,6 +40,13 @@
public static final String NAMESPACE_GD_URI =
"http://schemas.google.com/g/2005";
+ /** Namespace prefix for GData batch operations */
+ public static final String NAMESPACE_BATCH = "batch";
+
+ /** Namespace uri for GData batch operations */
+ public static final String NAMESPACE_BATCH_URI =
+ "http://schemas.google.com/gdata/batch";
+
private final InputStream is;
private final XmlPullParser parser;
private boolean isInBadState;
@@ -210,7 +220,6 @@
} else {
handleExtraElementInFeed(feed);
}
- break;
default:
break;
}
@@ -388,6 +397,30 @@
}
/**
+ * Supply a 'skipSubTree' API which, for some reason, the kxml2 pull parser
+ * hasn't implemented.
+ */
+ protected void skipSubTree()
+ throws XmlPullParserException, IOException {
+ // Iterate the remaining structure for this element, discarding events
+ // until we hit the element's corresponding end tag.
+ int level = 1;
+ while (level > 0) {
+ int eventType = parser.next();
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ ++level;
+ break;
+ case XmlPullParser.END_TAG:
+ --level;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
* Parses the current entry in the XML document. Assumes that the parser
* is currently pointing just at the beginning of an
* <entry>.
@@ -465,6 +498,8 @@
entry.setUpdateDate(XmlUtils.extractChildText(parser));
} else if ("deleted".equals(name)) {
entry.setDeleted(true);
+ } else if (NAMESPACE_BATCH_URI.equals(parser.getNamespace())) {
+ handleBatchInfo(entry);
} else {
handleExtraElementInEntry(entry);
}
@@ -517,6 +552,43 @@
}
}
+ private void handleBatchInfo(Entry entry)
+ throws IOException, XmlPullParserException {
+ String name = parser.getName();
+ if ("status".equals(name)) {
+ BatchStatus status = new BatchStatus();
+ BatchUtils.setBatchStatus(entry, status);
+ status.setStatusCode(getIntAttribute(parser, "code"));
+ status.setReason(getAttribute(parser, "reason"));
+ status.setContentType(getAttribute(parser, "content-type"));
+ // TODO: Read sub-tree into content.
+ skipSubTree();
+ } else if ("id".equals(name)) {
+ BatchUtils.setBatchId(entry, XmlUtils.extractChildText(parser));
+ } else if ("operation".equals(name)) {
+ BatchUtils.setBatchOperation(entry, getAttribute(parser, "type"));
+ } else if ("interrupted".equals(name)) {
+ BatchInterrupted interrupted = new BatchInterrupted();
+ BatchUtils.setBatchInterrupted(entry, interrupted);
+ interrupted.setReason(getAttribute(parser, "reason"));
+ interrupted.setErrorCount(getIntAttribute(parser, "error"));
+ interrupted.setSuccessCount(getIntAttribute(parser, "success"));
+ interrupted.setTotalCount(getIntAttribute(parser, "parsed"));
+ // TODO: Read sub-tree into content.
+ skipSubTree();
+ } else {
+ throw new XmlPullParserException("Unexpected batch element " + name);
+ }
+ }
+
+ private static String getAttribute(XmlPullParser parser, String name) {
+ return parser.getAttributeValue(null /* ns */, name);
+ }
+
+ private static int getIntAttribute(XmlPullParser parser, String name) {
+ return Integer.parseInt(getAttribute(parser, name));
+ }
+
/*
* (non-Javadoc)
* @see com.google.wireless.gdata2.parser.GDataParser#close()
diff --git a/src/com/google/wireless/gdata2/serializer/GDataSerializer.java b/src/com/google/wireless/gdata2/serializer/GDataSerializer.java
index 3d75485..e79ad80 100644
--- a/src/com/google/wireless/gdata2/serializer/GDataSerializer.java
+++ b/src/com/google/wireless/gdata2/serializer/GDataSerializer.java
@@ -31,6 +31,11 @@
public static final int FORMAT_UPDATE = 2;
/**
+ * Serialize the entry as part of a batch of operations.
+ */
+ public static final int FORMAT_BATCH = 3;
+
+ /**
* Returns the Content-Type for this serialization format.
* @return The Content-Type for this serialization format.
*/
@@ -43,6 +48,7 @@
* @see #FORMAT_FULL
* @see #FORMAT_CREATE
* @see #FORMAT_UPDATE
+ * @see #FORMAT_BATCH
*
* @param out The {@link OutputStream} to which the entry should be
* serialized.
diff --git a/src/com/google/wireless/gdata2/serializer/xml/XmlBatchGDataSerializer.java b/src/com/google/wireless/gdata2/serializer/xml/XmlBatchGDataSerializer.java
new file mode 100644
index 0000000..d929263
--- /dev/null
+++ b/src/com/google/wireless/gdata2/serializer/xml/XmlBatchGDataSerializer.java
@@ -0,0 +1,93 @@
+// Copyright 2008 Google Inc. All Rights Reserved.
+
+package com.google.wireless.gdata2.serializer.xml;
+
+import com.google.wireless.gdata2.serializer.GDataSerializer;
+import com.google.wireless.gdata2.parser.ParseException;
+import com.google.wireless.gdata2.parser.xml.XmlParserFactory;
+import com.google.wireless.gdata2.parser.xml.XmlGDataParser;
+import com.google.wireless.gdata2.client.GDataParserFactory;
+import com.google.wireless.gdata2.data.Entry;
+
+import org.xmlpull.v1.XmlSerializer;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Serializes a batch of GData requests as an XML stream.
+ */
+public class XmlBatchGDataSerializer implements GDataSerializer {
+
+ private final GDataParserFactory gdataFactory;
+ private final XmlParserFactory xmlFactory;
+ private final Enumeration batch;
+
+ /*
+ * Constructs an XmlBatchGDataSerializer for serializing the given batch
+ * of GData requests
+ *
+ * @param gdataFactory used to create serializers for individual requests
+ * @param xmlFactory used to create the XML stream
+ * @param Enumeration the batch of requests to serialize
+ */
+ public XmlBatchGDataSerializer(GDataParserFactory gdataFactory,
+ XmlParserFactory xmlFactory, Enumeration batch) {
+ this.gdataFactory = gdataFactory;
+ this.xmlFactory = xmlFactory;
+ this.batch = batch;
+ }
+
+ public String getContentType() {
+ return "application/atom+xml";
+ }
+
+ public void serialize(OutputStream out, int format)
+ throws IOException, ParseException {
+ XmlSerializer serializer;
+ try {
+ serializer = xmlFactory.createSerializer();
+ } catch (XmlPullParserException e) {
+ throw new ParseException("Unable to create XmlSerializer.", e);
+ }
+
+ serializer.setOutput(out, "UTF-8");
+ serializer.startDocument("UTF-8", new Boolean(false));
+
+ declareNamespaces(serializer);
+
+ boolean first = true;
+ while (batch.hasMoreElements()) {
+ Entry entry = (Entry) batch.nextElement();
+ XmlEntryGDataSerializer entrySerializer = (XmlEntryGDataSerializer)
+ gdataFactory.createSerializer(entry);
+
+ if (first) {
+ // Let the first entry serializer declare extra namespaces.
+ first = false;
+ serializer.startTag(XmlGDataParser.NAMESPACE_ATOM_URI, "feed");
+ entrySerializer.declareExtraEntryNamespaces(serializer);
+ }
+ entrySerializer.serialize(out, GDataSerializer.FORMAT_BATCH);
+ }
+
+ if (first) {
+ serializer.startTag(XmlGDataParser.NAMESPACE_ATOM_URI, "feed");
+ }
+
+ serializer.endTag(XmlGDataParser.NAMESPACE_ATOM_URI, "feed");
+ serializer.endDocument();
+ serializer.flush();
+ }
+
+ private static void declareNamespaces(XmlSerializer serializer) throws IOException {
+ serializer.setPrefix("" /* default ns */,
+ XmlGDataParser.NAMESPACE_ATOM_URI);
+ serializer.setPrefix(XmlGDataParser.NAMESPACE_GD,
+ XmlGDataParser.NAMESPACE_GD_URI);
+ serializer.setPrefix(XmlGDataParser.NAMESPACE_BATCH,
+ XmlGDataParser.NAMESPACE_BATCH_URI);
+ }
+}
diff --git a/src/com/google/wireless/gdata2/serializer/xml/XmlEntryGDataSerializer.java b/src/com/google/wireless/gdata2/serializer/xml/XmlEntryGDataSerializer.java
index 23036ea..654348f 100644
--- a/src/com/google/wireless/gdata2/serializer/xml/XmlEntryGDataSerializer.java
+++ b/src/com/google/wireless/gdata2/serializer/xml/XmlEntryGDataSerializer.java
@@ -2,6 +2,7 @@
package com.google.wireless.gdata2.serializer.xml;
+import com.google.wireless.gdata2.data.batch.BatchUtils;
import com.google.wireless.gdata2.data.Entry;
import com.google.wireless.gdata2.data.ExtendedProperty;
import com.google.wireless.gdata2.data.StringUtils;
@@ -68,15 +69,19 @@
// TODO: make the output compact
serializer.setOutput(out, "UTF-8");
- serializer.startDocument("UTF-8", new Boolean(false));
+ if (format != FORMAT_BATCH) {
+ serializer.startDocument("UTF-8", new Boolean(false));
+ declareEntryNamespaces(serializer);
+ }
- declareEntryNamespaces(serializer);
serializer.startTag(XmlGDataParser.NAMESPACE_ATOM_URI, "entry");
serializeEntryContents(serializer, format);
serializer.endTag(XmlGDataParser.NAMESPACE_ATOM_URI, "entry");
- serializer.endDocument();
+ if (format != FORMAT_BATCH) {
+ serializer.endDocument();
+ }
serializer.flush();
}
@@ -102,6 +107,10 @@
int format)
throws ParseException, IOException {
+ if (format == FORMAT_BATCH) {
+ serializeBatchInfo(serializer);
+ }
+
if (format != FORMAT_CREATE) {
serializeId(serializer, entry.getId());
}
@@ -277,4 +286,24 @@
serializer.text(updateDate);
serializer.endTag(null /* ns */, "updated");
}
+
+ private void serializeBatchInfo(XmlSerializer serializer)
+ throws IOException {
+ if (!StringUtils.isEmpty(entry.getETag())) {
+ serializer.attribute(XmlGDataParser.NAMESPACE_GD_URI, "etag",
+ entry.getETag());
+ }
+ if (!StringUtils.isEmpty(BatchUtils.getBatchOperation(entry))) {
+ serializer.startTag(XmlGDataParser.NAMESPACE_BATCH_URI, "operation");
+ serializer.attribute(null /* ns */, "type",
+ BatchUtils.getBatchOperation(entry));
+ serializer.endTag(XmlGDataParser.NAMESPACE_BATCH_URI, "operation");
+ }
+ if (!StringUtils.isEmpty(BatchUtils.getBatchId(entry))) {
+ serializer.startTag(XmlGDataParser.NAMESPACE_BATCH_URI, "id");
+ serializer.text(BatchUtils.getBatchId(entry));
+ serializer.endTag(XmlGDataParser.NAMESPACE_BATCH_URI, "id");
+ }
+ }
+
}