001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.common.xmap; 023 024import java.util.Map; 025 026import org.nuxeo.common.xmap.annotation.XNodeMap; 027import org.w3c.dom.Element; 028import org.w3c.dom.Node; 029 030/** 031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 032 */ 033public class XAnnotatedMap extends XAnnotatedList { 034 035 protected static final ElementMapVisitor elementMapVisitor = new ElementMapVisitor(); 036 037 protected static final ElementValueMapVisitor elementVisitor = new ElementValueMapVisitor(); 038 039 protected static final AttributeValueMapVisitor attributeVisitor = new AttributeValueMapVisitor(); 040 041 protected final Path key; 042 043 protected final boolean isNullByDefault; 044 045 public XAnnotatedMap(XMap xmap, XAccessor setter, XNodeMap anno) { 046 super(xmap, setter); 047 path = new Path(anno.value()); 048 trim = anno.trim(); 049 key = new Path(anno.key()); 050 type = anno.type(); 051 componentType = anno.componentType(); 052 valueFactory = xmap.getValueFactory(componentType); 053 xao = xmap.register(componentType); 054 isNullByDefault = anno.nullByDefault(); 055 } 056 057 @SuppressWarnings("unchecked") 058 @Override 059 protected Object getValue(Context ctx, Element base) { 060 Map<String, Object> values; 061 try { 062 values = (Map<String, Object>) type.getDeclaredConstructor().newInstance(); 063 } catch (ReflectiveOperationException e) { 064 throw new IllegalArgumentException(e); 065 } 066 if (xao != null) { 067 DOMHelper.visitMapNodes(ctx, this, base, path, elementMapVisitor, values); 068 } else { 069 if (path.attribute != null) { 070 // attribute list 071 DOMHelper.visitMapNodes(ctx, this, base, path, attributeVisitor, values); 072 } else { 073 // element list 074 DOMHelper.visitMapNodes(ctx, this, base, path, elementVisitor, values); 075 } 076 } 077 if (isNullByDefault && values.isEmpty()) { 078 values = null; 079 } 080 return values; 081 } 082 083 @Override 084 public void toXML(Object instance, Element parent) { 085 Object v = accessor.getValue(instance); 086 if (v instanceof Map<?, ?>) { 087 @SuppressWarnings("unchecked") 088 Map<String, ?> map = (Map<String, ?>) v; 089 if (xao == null) { 090 for (Map.Entry<String, ?> entry : map.entrySet()) { 091 String entryKey = entry.getKey(); 092 String value = valueFactory.serialize(null, entry.getValue()); 093 Element e = XMLBuilder.addElement(parent, path); 094 Element keyElement = XMLBuilder.getOrCreateElement(e, key); 095 XMLBuilder.fillField(keyElement, entryKey, key.attribute); 096 XMLBuilder.fillField(e, value, null); 097 } 098 } else { 099 for (Map.Entry<String, ?> entry : map.entrySet()) { 100 String entryKey = entry.getKey(); 101 Element e = XMLBuilder.addElement(parent, path); 102 Element keyElement = XMLBuilder.getOrCreateElement(e, key); 103 XMLBuilder.fillField(keyElement, entryKey, key.attribute); 104 XMLBuilder.toXML(entry.getValue(), e, xao); 105 } 106 } 107 } 108 } 109} 110 111class ElementMapVisitor implements DOMHelper.NodeMapVisitor { 112 113 @Override 114 public void visitNode(Context ctx, XAnnotatedMember xam, Node node, String key, Map<String, Object> result) { 115 result.put(key, xam.xao.newInstance(ctx, (Element) node)); 116 } 117} 118 119class ElementValueMapVisitor implements DOMHelper.NodeMapVisitor { 120 @Override 121 public void visitNode(Context ctx, XAnnotatedMember xam, Node node, String key, Map<String, Object> result) { 122 String val = node.getTextContent(); 123 if (xam.trim) { 124 val = val.trim(); 125 } 126 if (xam.valueFactory != null) { 127 result.put(key, xam.valueFactory.deserialize(ctx, val)); 128 } else { 129 // TODO: log warning? 130 result.put(key, val); 131 } 132 } 133} 134 135class AttributeValueMapVisitor implements DOMHelper.NodeMapVisitor { 136 @Override 137 public void visitNode(Context ctx, XAnnotatedMember xam, Node node, String key, Map<String, Object> result) { 138 String val = node.getNodeValue(); 139 if (xam.valueFactory != null) { 140 result.put(key, xam.valueFactory.deserialize(ctx, val)); 141 } else { 142 // TODO: log warning? 143 result.put(key, val); 144 } 145 } 146}