001package conexp.fx.core.xml; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2023 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.util.Collection; 026import java.util.Collections; 027import java.util.LinkedList; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.concurrent.ConcurrentHashMap; 032 033import org.jsoup.nodes.Element; 034 035import com.google.common.base.Function; 036import com.google.common.collect.Iterables; 037 038import conexp.fx.core.collections.Pair; 039 040public abstract class AbstractCompoundData extends Data<Map<String, Data<?>>> implements Map<String, Data<?>> { 041 042 private static final Function<Element, String> ELEMENT_TO_TEXT_FUNCTION = new Function<Element, String>() { 043 044 public final String apply(final Element element) { 045 return element.text(); 046 } 047 }; 048 049 public AbstractCompoundData(final Datatype type, final String key) { 050 super(type, key, new ConcurrentHashMap<String, Data<?>>()); 051 } 052 053 public AbstractCompoundData(final Datatype type, final String key, final Map<String, Data<?>> value) { 054 super(type, key, new ConcurrentHashMap<String, Data<?>>(value)); 055 } 056 057 public AbstractCompoundData(final Datatype type, final String key, final Element element, final Metadata metadata) 058 throws NullPointerException, IndexOutOfBoundsException { 059 super(type, key, readDataFromElement(element, metadata)); 060 } 061 062 protected synchronized static final Map<String, Data<?>> 063 readDataFromElement(final Element element, final Metadata metadata) { 064 final Map<String, Data<?>> map = new ConcurrentHashMap<String, Data<?>>(); 065 for (Map.Entry<String, Pair<Datatype, Metadata>> entry : metadata.getKeyDatatypeMap().entrySet()) { 066 final String key = entry.getKey(); 067 final Datatype type = entry.getValue().first(); 068 final Metadata _metadata = entry.getValue().second(); 069 final Element data = JsoupUtil.firstElement(element, Key.toArray(key)); 070 switch (type) { 071 case BOOLEAN: 072 map.put(key, new BooleanData(key, data.text())); 073 break; 074 case INTEGER: 075 map.put(key, new IntegerData(key, data.text())); 076 break; 077 case FLOAT: 078 map.put(key, new FloatData(key, data.text())); 079 break; 080 case STRING: 081 try { 082 map.put(key, new StringData(key, data.text())); 083 } catch (Exception e) { 084 System.err.println(data); 085 e.printStackTrace(); 086 } 087 break; 088 case COMPOUND: 089 map.put(key, new CompoundData(key, data, entry.getValue().second())); 090 break; 091 case BOOLEAN_LIST: 092 map.put(key, new BooleanListData(key, _metadata.getSubkey(), null, readStringDataFromElement(data, _metadata))); 093 break; 094 case INTEGER_LIST: 095 map.put(key, new IntegerListData(key, _metadata.getSubkey(), null, readStringDataFromElement(data, _metadata))); 096 break; 097 case FLOAT_LIST: 098 map.put(key, new FloatListData(key, _metadata.getSubkey(), null, readStringDataFromElement(data, _metadata))); 099 break; 100 case STRING_LIST: 101 map.put(key, new StringListData(key, _metadata.getSubkey(), readStringDataFromElement(data, _metadata))); 102 break; 103 case COMPOUND_LIST: 104 map.put(key, new CompoundListData(key, _metadata.getSubkey(), data, _metadata)); 105 case METADATA: 106 default: 107 } 108 } 109 return map; 110 } 111 112 protected static List<String> readStringDataFromElement(final Element element, final Metadata metadata) { 113 List<String> list = new LinkedList<String>(); 114 for (String value : Iterables 115 .transform(JsoupUtil.childrenByTag(element, metadata.getSubkey()), ELEMENT_TO_TEXT_FUNCTION)) 116 list.add(value); 117 return Collections.synchronizedList(list); 118 } 119 120 @Override 121 public final boolean isEmpty() { 122 return value.isEmpty(); 123 } 124 125 @Override 126 public final int size() { 127 return value.size(); 128 } 129 130 @Override 131 public final void clear() { 132 value.clear(); 133 } 134 135 @Override 136 public final boolean containsKey(Object key) { 137 return value.containsKey(key); 138 } 139 140 @Override 141 public final boolean containsValue(Object value) { 142 return this.value.containsValue(value); 143 } 144 145 @Override 146 public final Data<?> get(Object key) { 147 return value.get(key); 148 } 149 150 @Override 151 public final Data<?> put(String key, Data<?> value) { 152 return this.value.put(key, value); 153 } 154 155 @Override 156 public final void putAll(Map<? extends String, ? extends Data<?>> m) { 157 value.putAll(m); 158 } 159 160 @Override 161 public final Data<?> remove(Object key) { 162 return value.remove(key); 163 } 164 165 @Override 166 public final Set<String> keySet() { 167 return value.keySet(); 168 } 169 170 @Override 171 public final Collection<Data<?>> values() { 172 return value.values(); 173 } 174 175 @Override 176 public final Set<Map.Entry<String, Data<?>>> entrySet() { 177 return value.entrySet(); 178 } 179 180}