/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://opensource.org/licenses/cddl1.php * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at http://opensource.org/licenses/cddl1.php. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ package org.identityconnectors.framework.impl.serializer.xml; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import org.identityconnectors.common.Base64; import org.identityconnectors.common.XmlUtil; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.impl.serializer.ObjectDecoder; import org.identityconnectors.framework.impl.serializer.ObjectSerializationHandler; import org.identityconnectors.framework.impl.serializer.ObjectSerializerRegistry; import org.identityconnectors.framework.impl.serializer.ObjectTypeMapper; import org.w3c.dom.Attr; import org.w3c.dom.Element; public class XmlObjectDecoder implements ObjectDecoder { private final Element node; private final Class<?> expectedClass; public XmlObjectDecoder(Element node, Class<?> expectedClass) { this.node = node; this.expectedClass = expectedClass; } public Object readObject() { return readObjectInternal(); } public boolean readBooleanContents() { return decodeBoolean(readStringContentsInternal()); } public boolean readBooleanField(String fieldName, boolean dflt) { return decodeBoolean(readStringAttributeInternal(fieldName, XmlObjectEncoder .encodeBoolean(dflt))); } public byte readByteContents() { return decodeByte(readStringContentsInternal()); } public byte[] readByteArrayContents() { return decodeByteArray(readStringContentsInternal()); } public Class<?> readClassContents() { return decodeClass(readStringContentsInternal()); } public Class<?> readClassField(String name, Class<?> dflt) { String val = readStringAttributeInternal(name, null); if (val == null) { return dflt; } else { return decodeClass(val); } } public double readDoubleContents() { return decodeDouble(readStringContentsInternal()); } public double readDoubleField(String fieldName, double dflt) { return decodeDouble(readStringAttributeInternal(fieldName, XmlObjectEncoder .encodeDouble(dflt))); } public float readFloatContents() { return decodeFloat(readStringContentsInternal()); } public float readFloatField(String fieldName, float dflt) { return decodeFloat(readStringAttributeInternal(fieldName, XmlObjectEncoder .encodeFloat(dflt))); } public int readIntContents() { return decodeInt(readStringContentsInternal()); } public int readIntField(String fieldName, int dflt) { return decodeInt(readStringAttributeInternal(fieldName, XmlObjectEncoder.encodeInt(dflt))); } public long readLongContents() { return decodeLong(readStringContentsInternal()); } public long readLongField(String fieldName, long dflt) { return decodeLong(readStringAttributeInternal(fieldName, XmlObjectEncoder.encodeLong(dflt))); } public int getNumSubObjects() { int count = 0; for (Element subElement = XmlUtil.getFirstChildElement(node); subElement != null; subElement = XmlUtil.getNextElement(subElement)) { count++; } return count; } public Object readObjectContents(int index) { Element subElement = XmlUtil.getFirstChildElement(node); for (int i = 0; i < index; i++) { subElement = XmlUtil.getNextElement(subElement); } if (subElement == null) { throw new ConnectorException("Missing subelement number: " + index); } return new XmlObjectDecoder(subElement, null).readObject(); } public Object readObjectField(String fieldName, Class<?> expected, Object dflt) { Element child = XmlUtil.findImmediateChildElement(node, fieldName); if (child == null) { return dflt; } if (expected != null) { return new XmlObjectDecoder(child, expected).readObject(); } Element subElement = XmlUtil.getFirstChildElement(child); if (subElement == null) { return dflt; } // if they specify null, don't apply defaults return new XmlObjectDecoder(subElement, null).readObject(); } public String readStringContents() { String rv = readStringContentsInternal(); return rv == null ? "" : rv; } public String readStringField(String fieldName, String dflt) { return readStringAttributeInternal(fieldName, dflt); } private String readStringContentsInternal() { String xml = XmlUtil.getContent(node); return xml; } private String readStringAttributeInternal(String name, String dflt) { Attr attr = node.getAttributeNode(name); if (attr == null) { return dflt; } return attr.getValue(); } private boolean decodeBoolean(String v) { return Boolean.parseBoolean(v); } private byte decodeByte(String v) { return Byte.decode(v); } private byte[] decodeByteArray(String base64) { return Base64.decode(base64); } private Class<?> decodeClass(String type) { if (type.endsWith("[]")) { String componentName = type.substring(0, type.length() - "[]".length()); Class<?> componentClass = decodeClass(componentName); Class<?> arrayClass = Array.newInstance(componentClass, 0).getClass(); return arrayClass; } else { ObjectTypeMapper mapper = ObjectSerializerRegistry.getMapperBySerialType(type); if (mapper == null) { throw new ConnectorException("No deserializer for type: " + type); } Class<?> clazz = mapper.getHandledObjectType(); return clazz; } } private double decodeDouble(String val) { return Double.parseDouble(val); } private float decodeFloat(String val) { return Float.parseFloat(val); } private int decodeInt(String val) { return Integer.parseInt(val); } private long decodeLong(String val) { return Long.parseLong(val); } private Object readObjectInternal() { if (expectedClass != null) { ObjectSerializationHandler handler = ObjectSerializerRegistry.getHandlerByObjectType(expectedClass); if (handler == null) { if (expectedClass.isArray()) { List<Object> temp = new ArrayList<Object>(); for (Element child = XmlUtil.getFirstChildElement(node); child != null; child = XmlUtil.getNextElement(child)) { XmlObjectDecoder sub = new XmlObjectDecoder(child, null); Object obj = sub.readObject(); temp.add(obj); } int length = temp.size(); Object array = Array.newInstance(expectedClass.getComponentType(), length); for (int i = 0; i < length; i++) { Object element = temp.get(i); Array.set(array, i, element); } return array; } else { throw new ConnectorException("No deserializer for type: " + expectedClass); } } else { return handler.deserialize(this); } } else if (node.getTagName().equals("null")) { return null; } else if (node.getTagName().equals("Array")) { String componentType = XmlUtil.getAttribute(node, "componentType"); if (componentType == null) { componentType = "Object"; } Class<?> componentClass = decodeClass(componentType); List<Object> temp = new ArrayList<Object>(); for (Element child = XmlUtil.getFirstChildElement(node); child != null; child = XmlUtil.getNextElement(child)) { XmlObjectDecoder sub = new XmlObjectDecoder(child, null); Object obj = sub.readObject(); temp.add(obj); } int length = temp.size(); Object array = Array.newInstance(componentClass, length); for (int i = 0; i < length; i++) { Object element = temp.get(i); Array.set(array, i, element); } return array; } else { Class<?> clazz = decodeClass(node.getTagName()); ObjectSerializationHandler handler = ObjectSerializerRegistry.getHandlerByObjectType(clazz); if (handler == null) { throw new ConnectorException("No deserializer for type: " + clazz); } else { return handler.deserialize(this); } } } }