001/* 002 * (C) Copyright 2006-2018 Nuxeo (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 */ 019package org.nuxeo.common.xmap; 020 021import java.io.File; 022import java.net.MalformedURLException; 023import java.net.URL; 024import java.text.DateFormat; 025import java.text.ParseException; 026import java.time.Duration; 027import java.util.Date; 028import java.util.Hashtable; 029import java.util.Map; 030 031import org.nuxeo.common.utils.DurationUtils; 032import org.w3c.dom.Node; 033 034/** 035 * Value factories are used to decode values from XML strings. 036 * <p> 037 * To register a new factory for a given XMap instance use the method 038 * {@link XMap#setValueFactory(Class, XValueFactory)}. 039 * 040 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 041 */ 042public abstract class XValueFactory { 043 044 static final Map<Class<?>, XValueFactory> defaultFactories = new Hashtable<>(); 045 046 public abstract Object deserialize(Context context, String value); 047 048 public abstract String serialize(Context context, Object value); 049 050 public final Object getElementValue(Context context, Node element, boolean trim) { 051 String text = element.getTextContent(); 052 return deserialize(context, trim ? text.trim() : text); 053 } 054 055 public final Object getAttributeValue(Context context, Node element, String name) { 056 Node at = element.getAttributes().getNamedItem(name); 057 return at != null ? deserialize(context, at.getNodeValue()) : null; 058 } 059 060 public static void addFactory(Class<?> klass, XValueFactory factory) { 061 defaultFactories.put(klass, factory); 062 } 063 064 public static XValueFactory getFactory(Class<?> type) { 065 return defaultFactories.get(type); 066 } 067 068 public static Object getValue(Context context, Class<?> klass, String value) { 069 XValueFactory factory = defaultFactories.get(klass); 070 if (factory == null) { 071 return null; 072 } 073 return factory.deserialize(context, value); 074 } 075 076 public static final XValueFactory STRING = new XValueFactory() { 077 @Override 078 public Object deserialize(Context context, String value) { 079 return value; 080 } 081 082 @Override 083 public String serialize(Context context, Object value) { 084 return value.toString(); 085 } 086 }; 087 088 public static final XValueFactory INTEGER = new XValueFactory() { 089 @Override 090 public Object deserialize(Context context, String value) { 091 return Integer.valueOf(value); 092 } 093 094 @Override 095 public String serialize(Context context, Object value) { 096 return value.toString(); 097 } 098 }; 099 100 public static final XValueFactory LONG = new XValueFactory() { 101 @Override 102 public Object deserialize(Context context, String value) { 103 return Long.valueOf(value); 104 } 105 106 @Override 107 public String serialize(Context context, Object value) { 108 return value.toString(); 109 } 110 }; 111 112 public static final XValueFactory DOUBLE = new XValueFactory() { 113 @Override 114 public Object deserialize(Context context, String value) { 115 return Double.valueOf(value); 116 } 117 118 @Override 119 public String serialize(Context context, Object value) { 120 return value.toString(); 121 } 122 }; 123 124 public static final XValueFactory FLOAT = new XValueFactory() { 125 @Override 126 public Object deserialize(Context context, String value) { 127 return Float.valueOf(value); 128 } 129 130 @Override 131 public String serialize(Context context, Object value) { 132 return value.toString(); 133 } 134 }; 135 136 public static final XValueFactory BOOLEAN = new XValueFactory() { 137 @Override 138 public Object deserialize(Context context, String value) { 139 return Boolean.valueOf(value); 140 } 141 142 @Override 143 public String serialize(Context context, Object value) { 144 return value.toString(); 145 } 146 }; 147 148 public static final XValueFactory DATE = new XValueFactory() { 149 private final DateFormat df = DateFormat.getDateInstance(); 150 151 @Override 152 public Object deserialize(Context context, String value) { 153 try { 154 return df.parse(value); 155 } catch (ParseException e) { 156 return null; 157 } 158 } 159 160 @Override 161 public String serialize(Context context, Object value) { 162 Date date = (Date) value; 163 return df.format(date); 164 } 165 }; 166 167 public static final XValueFactory FILE = new XValueFactory() { 168 @Override 169 public Object deserialize(Context context, String value) { 170 return new File(value); 171 } 172 173 @Override 174 public String serialize(Context context, Object value) { 175 File file = (File) value; 176 return file.getName(); 177 } 178 }; 179 180 public static final XValueFactory URL = new XValueFactory() { 181 @Override 182 public Object deserialize(Context context, String value) { 183 try { 184 return new URL(value); 185 } catch (MalformedURLException e) { 186 return null; 187 } 188 } 189 190 @Override 191 public String serialize(Context context, Object value) { 192 return value.toString(); 193 } 194 }; 195 196 public static final XValueFactory CLASS = new XValueFactory() { 197 @Override 198 public Object deserialize(Context context, String value) { 199 try { 200 return context.loadClass(value); 201 } catch (ClassNotFoundException e) { 202 throw new XMapException("Cannot load class: " + value, e); 203 } 204 } 205 206 @Override 207 public String serialize(Context context, Object value) { 208 Class<?> clazz = (Class<?>) value; 209 return clazz.getName(); 210 } 211 }; 212 213 public static final XValueFactory RESOURCE = new XValueFactory() { 214 @Override 215 public Object deserialize(Context context, String value) { 216 return new Resource(context.getResource(value)); 217 } 218 219 @Override 220 public String serialize(Context context, Object value) { 221 return value.toString(); 222 } 223 }; 224 225 public static final XValueFactory DURATION = new XValueFactory() { 226 227 @Override 228 public Object deserialize(Context context, String value) { 229 return DurationUtils.parse(value); 230 } 231 232 @Override 233 public String serialize(Context context, Object value) { 234 // always use JDK format 235 return value.toString(); 236 } 237 }; 238 239 static { 240 addFactory(String.class, STRING); 241 addFactory(Integer.class, INTEGER); 242 addFactory(Long.class, LONG); 243 addFactory(Double.class, DOUBLE); 244 addFactory(Date.class, DATE); 245 addFactory(Boolean.class, BOOLEAN); 246 addFactory(File.class, FILE); 247 addFactory(URL.class, URL); 248 249 addFactory(int.class, INTEGER); 250 addFactory(long.class, LONG); 251 addFactory(double.class, DOUBLE); 252 addFactory(float.class, FLOAT); 253 addFactory(boolean.class, BOOLEAN); 254 255 addFactory(Class.class, CLASS); 256 addFactory(Resource.class, RESOURCE); 257 258 addFactory(Duration.class, DURATION); 259 } 260 261}