/*
* Copyright (C) 2009 JavaRosa
*
* 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.
*/
package org.openrosa.client.jr.xforms.util;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import org.openrosa.client.jr.core.data.IDataPointer;
import org.openrosa.client.jr.core.model.IAnswerDataSerializer;
import org.openrosa.client.jr.core.model.data.BooleanData;
import org.openrosa.client.jr.core.model.data.DateData;
import org.openrosa.client.jr.core.model.data.DateTimeData;
import org.openrosa.client.jr.core.model.data.DecimalData;
import org.openrosa.client.jr.core.model.data.GeoPointData;
import org.openrosa.client.jr.core.model.data.IAnswerData;
import org.openrosa.client.jr.core.model.data.IntegerData;
import org.openrosa.client.jr.core.model.data.MultiPointerAnswerData;
import org.openrosa.client.jr.core.model.data.PointerAnswerData;
import org.openrosa.client.jr.core.model.data.SelectMultiData;
import org.openrosa.client.jr.core.model.data.SelectOneData;
import org.openrosa.client.jr.core.model.data.StringData;
import org.openrosa.client.jr.core.model.data.TimeData;
import org.openrosa.client.jr.core.model.data.helper.Selection;
import org.openrosa.client.jr.core.model.utils.DateUtils;
import com.google.gwt.xml.client.Element;
/**
* The XFormAnswerDataSerializer takes in AnswerData objects, and provides
* an XForms compliant (String or Element) representation of that AnswerData.
*
* By default, this serializer can properly operate on StringData, DateData
* SelectMultiData, and SelectOneData AnswerData objects. This list can be
* extended by registering appropriate XForm serializing AnswerDataSerializers
* with this class.
*
* @author Clayton Sims
*
*/
public class XFormAnswerDataSerializer implements IAnswerDataSerializer {
public final static String DELIMITER = " ";
Vector additionalSerializers = new Vector();
public void registerAnswerSerializer(IAnswerDataSerializer ads) {
additionalSerializers.addElement(ads);
}
public boolean canSerialize(IAnswerData data) {
if (data instanceof StringData || data instanceof DateData || data instanceof TimeData ||
data instanceof SelectMultiData || data instanceof SelectOneData ||
data instanceof IntegerData || data instanceof DecimalData || data instanceof PointerAnswerData ||
data instanceof MultiPointerAnswerData || data instanceof GeoPointData || data instanceof DateTimeData) {
return true;
} else {
return false;
}
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains the given answer
*/
public Object serializeAnswerData(StringData data) {
return (String)data.getValue();
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains a date in xsd:date
* formatting
*/
public Object serializeAnswerData(DateData data) {
return DateUtils.formatDate((Date)data.getValue(), DateUtils.FORMAT_ISO8601);
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains a date in xsd:date
* formatting
*/
public Object serializeAnswerData(DateTimeData data) {
return DateUtils.formatDateTime((Date)data.getValue(), DateUtils.FORMAT_ISO8601);
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains a date in xsd:time
* formatting
*/
public Object serializeAnswerData(TimeData data) {
return DateUtils.formatTime((Date)data.getValue(), DateUtils.FORMAT_ISO8601);
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains a reference to the
* data
*/
public Object serializeAnswerData(PointerAnswerData data) {
//Note: In order to override this default behavior, a
//new serializer should be used, and then registered
//with this serializer
IDataPointer pointer = (IDataPointer)data.getValue();
return pointer.getDisplayText();
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains a reference to the
* data
*/
public Object serializeAnswerData(MultiPointerAnswerData data) {
//Note: In order to override this default behavior, a
//new serializer should be used, and then registered
//with this serializer
IDataPointer[] pointers = (IDataPointer[])data.getValue();
if(pointers.length == 1) {
return pointers[0].getDisplayText();
}
//TODO ???????????????????
/*Element parent = new Element();
for(int i = 0; i < pointers.length; ++i) {
Element datael = new Element();
datael.setName("data");
datael.addChild(Element.TEXT, pointers[i].getDisplayText());
parent.addChild(Element.ELEMENT, datael);
}
return parent;*/
return null;
}
/**
* @param data The AnswerDataObject to be serialized
* @return A string containing the xforms compliant format
* for a <select> tag, a string containing a list of answers
* separated by space characters.
*/
public Object serializeAnswerData(SelectMultiData data) {
Vector selections = (Vector)data.getValue();
Enumeration en = selections.elements();
StringBuffer selectString = new StringBuffer();
while(en.hasMoreElements()) {
Selection selection = (Selection)en.nextElement();
if (selectString.length() > 0)
selectString.append(DELIMITER);
selectString.append(selection.getValue());
}
//As Crazy, and stupid, as it sounds, this is the XForms specification
//for storing multiple selections.
return selectString.toString();
}
/**
* @param data The AnswerDataObject to be serialized
* @return A String which contains the value of a selection
*/
public Object serializeAnswerData(SelectOneData data) {
return ((Selection)data.getValue()).getValue();
}
public Object serializeAnswerData(IntegerData data) {
return ((Integer)data.getValue()).toString();
}
public Object serializeAnswerData(DecimalData data) {
return ((Double)data.getValue()).toString();
}
public Object serializeAnswerData(GeoPointData data) {
return data.getDisplayText();
}
public Object serializeAnswerData(BooleanData data) {
if(((Boolean)data.getValue()).booleanValue()) {
return "1";
} else {
return "0";
}
}
public Object serializeAnswerData(IAnswerData data, int dataType) {
// First, we want to go through the additional serializers, as they should
// take priority to the default serializations
Enumeration en = additionalSerializers.elements();
while(en.hasMoreElements()) {
IAnswerDataSerializer serializer = (IAnswerDataSerializer)en.nextElement();
if(serializer.canSerialize(data)) {
return serializer.serializeAnswerData(data, dataType);
}
}
//Defaults
Object result = serializeAnswerData(data);
return result;
}
public Object serializeAnswerData(IAnswerData data) {
if (data instanceof StringData) {
return serializeAnswerData((StringData)data);
} else if (data instanceof SelectMultiData) {
return serializeAnswerData((SelectMultiData)data);
} else if (data instanceof SelectOneData) {
return serializeAnswerData((SelectOneData)data);
} else if (data instanceof IntegerData){
return serializeAnswerData((IntegerData)data);
} else if (data instanceof DecimalData) {
return serializeAnswerData((DecimalData)data);
} else if (data instanceof DateData) {
return serializeAnswerData((DateData)data);
} else if (data instanceof TimeData) {
return serializeAnswerData((TimeData)data);
} else if (data instanceof PointerAnswerData) {
return serializeAnswerData((PointerAnswerData)data);
} else if (data instanceof MultiPointerAnswerData) {
return serializeAnswerData((MultiPointerAnswerData)data);
} else if (data instanceof GeoPointData) {
return serializeAnswerData((GeoPointData)data);
} else if (data instanceof DateTimeData) {
return serializeAnswerData((DateTimeData)data);
} else if (data instanceof BooleanData) {
return serializeAnswerData((BooleanData)data);
}
return null;
}
/*
* (non-Javadoc)
* @see org.javarosa.core.model.IAnswerDataSerializer#containsExternalData(org.javarosa.core.model.data.IAnswerData)
*/
public Boolean containsExternalData(IAnswerData data) {
//First check for registered serializers to identify whether
//they override this one.
Enumeration en = additionalSerializers.elements();
while(en.hasMoreElements()) {
IAnswerDataSerializer serializer = (IAnswerDataSerializer)en.nextElement();
Boolean contains = serializer.containsExternalData(data);
if(contains != null) {
return contains;
}
}
if( data instanceof PointerAnswerData ||
data instanceof MultiPointerAnswerData ) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
public IDataPointer[] retrieveExternalDataPointer(IAnswerData data) {
Enumeration en = additionalSerializers.elements();
while(en.hasMoreElements()) {
IAnswerDataSerializer serializer = (IAnswerDataSerializer)en.nextElement();
Boolean contains = serializer.containsExternalData(data);
if(contains != null) {
return serializer.retrieveExternalDataPointer(data);
}
}
if( data instanceof PointerAnswerData) {
IDataPointer[] pointer = new IDataPointer[1];
pointer[0] = (IDataPointer)((PointerAnswerData)data).getValue();
return pointer;
}
else if (data instanceof MultiPointerAnswerData ) {
return (IDataPointer[])((MultiPointerAnswerData)data).getValue();
}
//This shouldn't have been called.
return null;
}
}