/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. The ASF 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.abdera.ext.serializer;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.abdera.ext.serializer.annotation.Attribute;
import org.apache.abdera.ext.serializer.annotation.BaseURI;
import org.apache.abdera.ext.serializer.annotation.Extension;
import org.apache.abdera.ext.serializer.annotation.Language;
import org.apache.abdera.ext.serializer.annotation.Value;
import org.apache.abdera.ext.serializer.impl.ExtensionSerializer;
import org.apache.abdera.ext.serializer.impl.SimpleElementSerializer;
import org.apache.abdera.i18n.rfc4646.Lang;
import org.apache.abdera.writer.StreamWriter;
@SuppressWarnings("unchecked")
public abstract class BaseSerializer
extends Serializer {
public static final String DEFAULT = "##default";
protected abstract void init(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions);
protected abstract void finish(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions);
protected void process(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
}
public void serialize(
Object source,
ObjectContext objectContext,
SerializationContext context) {
Conventions conventions =
((ConventionSerializationContext)context)
.getConventions();
init(
source,
objectContext,
context,
conventions);
process(source, objectContext, context, conventions);
finish(
source,
objectContext,
context,
conventions);
}
protected void writeTextValue(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
AccessibleObject accessor =
objectContext.getAccessor(
Value.class,
conventions);
Object value = null;
if (accessor != null) {
value = eval(accessor, source);
}
context.getStreamWriter()
.writeElementText(
value != null ?
toString(value) :
toString(source));
}
protected void writeExtensions(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
AccessibleObject[] accessors = objectContext.getAccessors(Extension.class, conventions);
for (AccessibleObject accessor : accessors) {
Object value = eval(accessor,source);
ObjectContext valueContext = new ObjectContext(value,source,accessor);
Extension extension = valueContext.getAnnotation(Extension.class);
boolean simple = extension != null ? extension.simple() : false;
Serializer ser = context.getSerializer(valueContext);
if (ser == null) {
if (simple) {
QName qname = getQName(accessor);
ser = new SimpleElementSerializer(qname);
} else {
ser = context.getSerializer(valueContext);
if (ser == null) {
QName qname = getQName(accessor);
ser = new ExtensionSerializer(qname);
}
}
}
ser.serialize(value, valueContext, context);
}
}
protected void writeAttributes(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
writeCommon(source, objectContext, context, conventions);
StreamWriter sw = context.getStreamWriter();
AccessibleObject[] accessors = objectContext.getAccessors(Attribute.class, conventions);
for (AccessibleObject accessor : accessors) {
QName qname = getQName(accessor);
Object value = eval(accessor, source);
if (value != null)
sw.writeAttribute(qname, toString(value));
}
}
protected boolean writeElement(
Class<? extends Annotation> annotation,
Serializer serializer,
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
AccessibleObject accessor = objectContext.getAccessor(annotation, conventions);
if (accessor != null) {
Object value = eval(accessor, source);
ObjectContext valueContext = new ObjectContext(value,source,accessor);
serializer.serialize(value, valueContext, context);
return true;
}
return false;
}
protected void writeElements(
Class<? extends Annotation> annotation,
Serializer serializer,
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
AccessibleObject[] accessors = objectContext.getAccessors(annotation, conventions);
for (AccessibleObject accessor : accessors) {
if (accessor != null) {
Object value = eval(accessor, source);
Object[] values = toArray(value);
for (Object val : values) {
ObjectContext valueContext = new ObjectContext(val,source,accessor);
serializer.serialize(val, valueContext, context);
}
}
}
}
public static Object eval(AccessibleObject accessor, Object parent) {
try {
if (accessor instanceof Field)
return ((Field)accessor).get(parent);
else if (accessor instanceof Method)
return ((Method)accessor).invoke(parent, new Object[0]);
else return null;
} catch (Throwable t) {
throw new SerializationException(t);
}
}
protected boolean hasAnnotation(
AnnotatedElement item,
Class<? extends Annotation> annotation) {
return item.isAnnotationPresent(annotation);
}
protected void writeElement(StreamWriter sw, QName qname, String value) {
sw.startElement(qname)
.writeElementText(value)
.endElement();
}
public static String toString(Object value) {
if (value == null) return null;
Object[] values = toArray(value);
StringBuilder buf = new StringBuilder();
for (int n= 0; n < values.length; n++) {
if (n > 0) buf.append(", ");
buf.append(values[n].toString());
}
return buf.toString();
}
public static Object[] toArray(Object value) {
if (value == null) return new Object[0];
if (value.getClass().isArray()) {
return (Object[])value;
} else if (value instanceof Collection) {
return ((Collection)value).toArray();
} else if (value instanceof Map) {
return ((Map)value).values().toArray();
} else if (value instanceof Dictionary) {
List<Object> list = new ArrayList<Object>();
Enumeration e = ((Dictionary)value).elements();
while(e.hasMoreElements()) list.add(e.nextElement());
return list.toArray();
} else if (value instanceof Iterator) {
List<Object> list = new ArrayList<Object>();
Iterator i = (Iterator) value;
while(i.hasNext()) list.add(i.next());
return list.toArray();
} else if (value instanceof Enumeration) {
List<Object> list = new ArrayList<Object>();
Enumeration e = (Enumeration) value;
while(e.hasMoreElements()) list.add(e.nextElement());
return list.toArray();
} else if (value instanceof Iterable) {
List<Object> list = new ArrayList<Object>();
Iterable v = (Iterable) value;
Iterator i = v.iterator();
while(i.hasNext()) list.add(i.next());
return list.toArray();
} else {
return new Object[] {value};
}
}
protected static boolean isUndefined(String value) {
return value == null || DEFAULT.equals(value);
}
protected static QName getQName(AccessibleObject accessor) {
Extension ext = accessor.getAnnotation(Extension.class);
if (ext != null) return getQName(ext);
Attribute attr = accessor.getAnnotation(Attribute.class);
if (attr != null) return getQName(attr);
return new QName(
accessor instanceof Method ?
((Method)accessor).getName() :
((Field)accessor).getName());
}
protected static QName getQName(
Extension extension) {
QName qname = null;
if (extension != null) {
if (isUndefined(extension.prefix()) &&
isUndefined(extension.ns()) &&
isUndefined(extension.name())) {
qname = new QName(
extension.ns(),
extension.name(),
extension.prefix());
} else if (
isUndefined(extension.prefix()) &&
!isUndefined(extension.ns()) &&
!isUndefined(extension.name())) {
qname = new QName(
extension.ns(),
extension.name());
} else if (!isUndefined(extension.name())) {
qname = new QName(extension.name());
}
}
return qname;
}
protected static QName getQName(
Attribute attribute) {
QName qname = null;
if (attribute != null) {
if (isUndefined(attribute.prefix()) &&
isUndefined(attribute.ns()) &&
isUndefined(attribute.name())) {
qname = new QName(
attribute.ns(),
attribute.name(),
attribute.prefix());
} else if (
isUndefined(attribute.prefix()) &&
!isUndefined(attribute.ns()) &&
!isUndefined(attribute.name())) {
qname = new QName(
attribute.ns(),
attribute.name());
} else if (!isUndefined(attribute.name())) {
qname = new QName(attribute.name());
}
}
return qname;
}
@SuppressWarnings("deprecation")
protected void writeCommon(
Object source,
ObjectContext objectContext,
SerializationContext context,
Conventions conventions) {
StreamWriter sw = context.getStreamWriter();
String lang = null;
AccessibleObject accessor = objectContext.getAccessor(Language.class, conventions);
if (accessor != null) {
Object value = eval(accessor, source);
if (value != null) {
if (value instanceof Lang ||
value instanceof org.apache.abdera.i18n.lang.Lang) {
lang = value.toString();
} else {
lang = toString(value);
}
}
}
if (lang == null) {
Language _lang = objectContext.getAnnotation(Language.class);
if (_lang != null && !_lang.value().equals(DEFAULT)) {
lang = _lang.value();
}
}
if (lang != null)
sw.writeLanguage(lang);
String base = null;
accessor = objectContext.getAccessor(BaseURI.class, conventions);
if (accessor != null) {
Object value = eval(accessor, source);
if (value != null)
base = toString(value);
}
if (base != null)
sw.writeBase(base);
}
}