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