KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > datatypes > DataTypes


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10
11 package org.mmbase.datatypes;
12
13 import java.net.*;
14 import java.util.*;
15 import javax.xml.parsers.DocumentBuilder JavaDoc;
16 import org.xml.sax.InputSource JavaDoc;
17 import org.w3c.dom.*;
18
19 import org.mmbase.bridge.Node;
20 import org.mmbase.bridge.Field;
21 import org.mmbase.core.util.Fields;
22 import org.mmbase.datatypes.util.xml.*;
23 import org.mmbase.util.*;
24 import org.mmbase.util.xml.DocumentReader;
25 import org.mmbase.util.logging.*;
26
27 /**
28  * <p>
29  * This class contains various methods for manipulating DataType objects.
30  * It contains a static set of named DataType objects, with which it is possible to craete a set
31  * of datatypes that are accessable throught the MMBase application.
32  * This set contains, at the very least, the basic datatypes (a DataType for every
33  * 'MMBase' type, i.e. integer, string, etc).
34  * There can be only one DataType in a set with a given name, so it is not possible to have multiple
35  * registered datatypes with the same name.
36  * </p>
37  * <p>
38  * A number of other methods in this class deal with conversion, creating datatypes, and 'finishing'
39  * datatypes (locking a datatype to protect it form being changed).
40  *</p>
41  * @author Pierre van Rooden
42  * @since MMBase-1.8
43  * @version $Id: DataTypes.java,v 1.21 2006/05/16 21:11:05 michiel Exp $
44  */

45
46 public class DataTypes {
47
48     private static final Logger log = Logging.getLoggerInstance(DataTypes.class);
49
50     // the datatype collector containing named DataTypes for use throughout the application
51
private static final DataTypeCollector dataTypeCollector = DataTypeCollector.createSystemDataTypeCollector();
52
53     public static void initialize() {
54         // read the XML
55
// Watching will ptobably not work properly,
56
// as datatypes depend one ach other, and are are referred
57
// throughout the system.
58
// For the moment turn watching off.
59
// Not sure if it is needed anyway - it won't actually happen that often
60
log.trace("" + Constants.class); // make sure its static init is called, otherwise it goes horribly wrong.
61

62         log.debug("Reading datatypes " + dataTypeCollector);
63         readDataTypes(ResourceLoader.getConfigurationRoot(), "datatypes.xml");
64
65         /*
66         try {
67             ResourceWatcher watcher = new ResourceWatcher(ResourceLoader.getConfigurationRoot()) {
68                     public void onChange(String resource) {
69                         readDataTypes(getResourceLoader(), resource);
70                     }
71                 };
72             watcher.add("datatypes.xml");
73             watcher.start();
74             watcher.onChange("datatypes.xml");
75         } catch (Throwable t) {
76             log.error(t.getClass().getName() + ": " + Logging.stackTrace(t));
77         }
78         */

79
80     }
81
82     /**
83      * Initialize the type handlers defaultly supported by the system, plus those configured in WEB-INF/config.
84      */

85     private static void readDataTypes(ResourceLoader loader, String JavaDoc resource) {
86         List resources = loader.getResourceList(resource);
87         if (log.isDebugEnabled()) log.debug("Using " + resources);
88         ListIterator i = resources.listIterator();
89         while (i.hasNext()) i.next();
90         while (i.hasPrevious()) {
91             try {
92                 URL u = (URL) i.previous();
93                 URLConnection con = u.openConnection();
94                 if (con.getDoInput()) {
95                     InputSource JavaDoc dataTypesSource = new InputSource JavaDoc(con.getInputStream());
96                     dataTypesSource.setSystemId(u.toExternalForm());
97                     DocumentBuilder JavaDoc db = DocumentReader.getDocumentBuilder(true, true, new XMLErrorHandler(), new XMLEntityResolver(true, DataTypeReader.class));
98                     Document doc = db.parse(dataTypesSource);
99                     Element dataTypesElement = doc.getDocumentElement(); // fieldtypedefinitons or datatypes element
100
DataTypeReader.readDataTypes(dataTypesElement, dataTypeCollector);
101                 }
102             } catch (Exception JavaDoc e) {
103                 log.error(e.getMessage(), e);
104             }
105         }
106         if (log.isDebugEnabled()) log.debug(dataTypeCollector.toString());
107     }
108
109     /**
110      * Create an instance of a DataType based on the class passed.
111      * The DataType returned is, if possible, a specialized DataType (such as {@link IntegerDataType})
112      * based on the MMBase Type that most closely matches the passed class. Otherwise, it is a generic DataType
113      * specific for that class (with generally means that it only supports basic functionality such as autocast).
114      * @param name The name of the datatype to create. If <code>null</code> is passed, the class name is used.
115      * @param classType The class of the datatype to create. If <code>null</code> is passed, the
116       * dataType returned is based on Object.class.
117      */

118     public static BasicDataType createDataType(String JavaDoc name, Class JavaDoc classType) {
119         int type = Fields.classToType(classType);
120         if (name == null && classType != null) {
121             name = classType.getName();
122         }
123         if (type != Field.TYPE_UNKNOWN || classType == null) {
124             return createDataType(name, type, classType.isPrimitive());
125         } else {
126             return new BasicDataType(name, classType);
127         }
128     }
129
130     /**
131      * Create an instance of a DataType based on the MMBase type passed.
132      *
133      * @param primitive in case of integer, long, float, double, boolean this
134      * parameter determines whether a primitive type or the wrapper class
135      * should be used
136      */

137     private static BasicDataType createDataType(String JavaDoc name, int type, boolean primitive) {
138         switch (type) {
139         case Field.TYPE_BINARY: return new BinaryDataType(name);
140         case Field.TYPE_INTEGER : return new IntegerDataType(name, primitive);
141         case Field.TYPE_LONG: return new LongDataType(name, primitive);
142         case Field.TYPE_FLOAT: return new FloatDataType(name, primitive);
143         case Field.TYPE_DOUBLE: return new DoubleDataType(name, primitive);
144         case Field.TYPE_BOOLEAN: return new BooleanDataType(name, primitive);
145         case Field.TYPE_STRING : return new StringDataType(name);
146         case Field.TYPE_XML: return new XmlDataType(name);
147         case Field.TYPE_NODE: return new NodeDataType(name);
148         case Field.TYPE_DATETIME: return new DateTimeDataType(name);
149         case Field.TYPE_LIST: return new ListDataType(name);
150         default: return new BasicDataType(name);
151         }
152     }
153     /**
154      * Create an instance of a DataType based on the MMBase type passed. In case
155      * a type is used that has both a primitive and a wrapper class the wrapped
156      * version will be used.
157      */

158     private static BasicDataType createDataType(String JavaDoc name, int type) {
159         return createDataType(name, type, false);
160     }
161
162     /**
163      * Add an instance of a DataType to the set of data types that are available thoughout the application.
164      * The datatype should have a proper name, and not occur already in the set.
165      * Note that the datatype is finished when added (if it wasn't already), and can thereafter not be changed.
166      * @param dataType the datatype to add
167      * @return the dataType added.
168      * @throws IllegalArgumentException if the datatype does not have a name or already occurs in the set
169      */

170     public static DataType addFinalDataType(BasicDataType dataType) {
171         String JavaDoc name = dataType.getName();
172         if (name == null) {
173             throw new IllegalArgumentException JavaDoc("Passed datatype " + dataType + " does not have a name assigned.");
174         }
175         if (dataTypeCollector.contains(name)) {
176             throw new IllegalArgumentException JavaDoc("The datatype " + dataType + " was passed, but a type with the same name occurs as : " +
177                                                getDataType(name));
178         }
179         dataTypeCollector.finish(dataType);
180         dataTypeCollector.addDataType(dataType);
181         return dataType;
182     }
183
184     /**
185      * Returns a DataType from the the available set of datatypes accessible throughout the application,
186      * or <code>null</code> if that type does not exist.
187      * @param name the name of the DataType to look for
188      * @return A DataType instance or <code>null</code> if none can be found
189      */

190     public static synchronized BasicDataType getDataType(String JavaDoc name) {
191         return dataTypeCollector.getDataType(name);
192     }
193
194     /**
195      * Returns a DataType instance.
196      * The system first tries to obtain a data type from the available set of datatypes
197      * accessible throughout the application. If a DataType of the passed name exists, a clone of that DataType is returned.
198      * Otherwise, a clone of the base DataType passed is returned.
199      * if the DataType with the passed name does not exist, and the value passed for the baseDataType is <code>null</code>,
200      * the method returns <code>null</code>.
201      * @param name the name of the DataType to look for
202      * @param baseDataType the dataType to match against. Can be <code>null</code>.
203      * @return A DataType instance or <code>null</code> if none can be instantiated
204      */

205     public static synchronized BasicDataType getDataTypeInstance(String JavaDoc name, BasicDataType baseDataType) {
206         return dataTypeCollector.getDataTypeInstance(name, baseDataType);
207     }
208
209     /**
210      * Returns a DataType instance.
211      * The system first tries to obtain a type from the available set of datatypes
212      * accessible throughout the application. If a DataType of the passed name exists,
213      * a clone of that DataType is returned. Otherwise, an instance of a DataType based
214      * on the base type is returned.
215      * @param name the name of the DataType to look for
216      * @param type the base type to use for a default datatype instance
217      * @return A DataType instance
218      */

219     public static synchronized BasicDataType getDataTypeInstance(String JavaDoc name, int type) {
220         return getDataTypeInstance(name, getDataType(type));
221     }
222
223     /**
224      * Returns a ListDataType instance.
225      * The system first tries to obtain a type from the available set of datatypes
226      * accessible throughout the application. If a DataType of the passed name exists,
227      * a clone of that DataType is returned. Otherwise, an instance of a ListDataType based
228      * on the list item type is returned.
229      * @param name the name of the DataType to look for
230      * @param listItemType the base type to use for a default listdatatype instance
231      * (this type determines the type of the list elements)
232      * @return A ListDataType instance
233      */

234     public static synchronized ListDataType getListDataTypeInstance(String JavaDoc name, int listItemType) {
235         return (ListDataType)getDataTypeInstance(name, getListDataType(listItemType));
236     }
237
238     /**
239      * Returns the basic DataType that matches the passed type.
240      * The datatype is retrieved from the available set of datatypes accessible throughout the application.
241      * If this datatype does not (yet) exists, an instance is automatically created and added.
242      * The datatype returned by this method is only useful for matching or cloning - it cannot be changed.
243      * @param type the base type whose DataType to return
244      * @return the DataType instance
245      */

246     public static synchronized BasicDataType getDataType(int type) {
247         String JavaDoc name = Fields.getTypeDescription(type).toLowerCase();
248         BasicDataType dataType = getDataType(name);
249         if (dataType == null) {
250             if (type == Field.TYPE_LIST) {
251                 dataType = getListDataType(Field.TYPE_UNKNOWN);
252             } else {
253                 dataType = createDataType(name, type);
254                 // dataTypeCollector.finish(dataType); // will be finished when reading the XML.
255
dataTypeCollector.addDataType(dataType);
256             }
257         }
258         return dataType;
259     }
260
261     /**
262      * Returns the basic ListDataType whose item's DataType matches the passed type.
263      * The datatype is retrieved from the available set of datatypes accessible throughout the application.
264      * If this datatype does not (yet) exists, an instance is automatically created and added.
265      * The datatype returned by this method is only useful for matching or cloning - it cannot be changed.
266      * @param listItemType the base type whose ListDataType to return
267      * @return the ListDataType instance
268      */

269     public static ListDataType getListDataType(int listItemType) {
270         String JavaDoc name = Fields.getTypeDescription(Field.TYPE_LIST).toLowerCase() +
271                       "[" + Fields.getTypeDescription(listItemType).toLowerCase() + "]";
272         ListDataType dataType = (ListDataType) getDataType(name);
273         if (dataType == null) {
274             dataType = (ListDataType)createDataType(name, Field.TYPE_LIST);
275             dataType.setItemDataType(getDataType(listItemType));
276             dataTypeCollector.finish(dataType);
277             dataTypeCollector.addDataType(dataType);
278         }
279         return dataType;
280     }
281
282     public static DataTypeCollector getSystemCollector() {
283         return dataTypeCollector;
284     }
285
286
287     /**
288      * Returns a new XML completely describing the given DataType.
289      * This means that the XML will <em>not</em> have a base attribute.
290      */

291     public static Document toXml(DataType dataType) {
292         // create an inheritance stack
293
List stack = new ArrayList();
294         stack.add(dataType);
295         while (dataType.getOrigin() != null) {
296             dataType = dataType.getOrigin();
297             stack.add(0, dataType);
298         }
299
300         // new XML
301
Document doc = DocumentReader.getDocumentBuilder().newDocument();
302
303         // iterate the stack to completely resolve everything.
304
Iterator i = stack.iterator();
305         dataType = (DataType) i.next();
306         Element e = (Element) doc.importNode(dataType.toXml(), true);
307         doc.appendChild(e);
308         while (i.hasNext()) {
309             dataType = (DataType) i.next();
310             dataType.toXml(e);
311         }
312         return doc;
313     }
314
315 }
316
Popular Tags