001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.util.xml;
011:
012: import java.util.*;
013: import java.util.Map.Entry;
014:
015: import org.mmbase.module.core.MMObjectBuilder;
016: import org.mmbase.bridge.NodeManager;
017: import org.mmbase.core.CoreField;
018: import org.mmbase.core.util.Fields;
019: import org.mmbase.datatypes.DataType;
020: import org.mmbase.util.XMLEntityResolver;
021:
022: import org.w3c.dom.*;
023:
024: /**
025: * Class for creating builder configuration documents.
026: * Use this class to create a DOM document for a given builder.
027: * The document can then be used internally or serialized using a number of
028: * utility methods.
029: * This writer takes extension of builders (inheritance) into account.
030: *
031: * XXX This class actually transforms nice builder XML's to stupid automatic XML's in deprecated format, forgetting all comments, alls datatype extensions.
032: * TODO: This is broken!
033: *
034: * @since MMBase-1.6
035: * @author Pierre van Rooden
036: * @version $Id: BuilderWriter.java,v 1.26 2007/02/11 20:05:50 nklasens Exp $
037: */
038: public class BuilderWriter extends DocumentWriter {
039:
040: /**
041: * If true, the builder will expand when writing.
042: * Expanding means that all data of a builder is written, including non-overriden data
043: * from parent builders.
044: */
045: private boolean expandBuilder = false;
046: /**
047: * Hold a reference to the builder for which to create an XML document.
048: */
049: private MMObjectBuilder builder;
050:
051: /**
052: * Constructs the document writer.
053: * The constructor calls its super to create a basic document, based on the builder document type.
054: * @param builder the builder for which to create an XML document.
055: */
056: public BuilderWriter(MMObjectBuilder builder) throws DOMException {
057: super ("builder", BuilderReader.PUBLIC_ID_BUILDER,
058: XMLEntityResolver.DOMAIN
059: + XMLEntityResolver.DTD_SUBPATH
060: + BuilderReader.DTD_BUILDER);
061: this .builder = builder;
062: getMessageRetriever("org.mmbase.util.xml.resources.builderwriter");
063: }
064:
065: /**
066: * Generates the document. Can only be called once.
067: * @throws DOMException when an error occurred during generation
068: */
069: protected void generate() throws DOMException {
070: Element root = document.getDocumentElement();
071: addComment("builder.configuration", builder.getTableName(),
072: root);
073: root.setAttribute("name", "" + builder.getTableName());
074: root.setAttribute("maintainer", builder.getMaintainer());
075: root.setAttribute("version", "" + builder.getVersion());
076: MMObjectBuilder parent = null;
077: if (!expandBuilder) {
078: parent = builder.getParentBuilder();
079: if (parent != null) {
080: root.setAttribute("extends", parent.getTableName());
081: }
082: }
083: // status
084: addComment("builder.status", root);
085: addContentElement("status", "active", root);
086: // classfile
087: String data = builder.getClass().getName();
088: if ((parent == null)
089: || (!parent.getClass().getName().equals(data))) {
090: // strip - do we want it like this?
091: if (data.startsWith("org.mmbase.module.builders.")) {
092: data = data.substring(27);
093: }
094: addComment("builder.classfile", root);
095: addContentElement("classfile", data, root);
096: }
097: //searchage
098: data = builder.getSearchAge();
099: if ((parent == null) || (!parent.getSearchAge().equals(data))) {
100: addComment("builder.searchage", root);
101: addContentElement("searchage", data, root);
102: }
103: // names
104: Element names = document.createElement("names");
105: addComment("builder.names", root);
106: root.appendChild(names);
107: // names.singular
108: Map<String, String> datamap = builder.getSingularNames();
109: addComment("builder.singular", names);
110: for (Entry<String, String> em : datamap.entrySet()) {
111: String language = em.getKey();
112: String name = em.getValue();
113: if ((parent == null)
114: || !(name.equals(parent.getSingularName(language)))) {
115: Element elm = addContentElement("singular", name, names);
116: elm.setAttribute("xml:lang", language);
117: }
118: }
119: // names.plural
120: datamap = builder.getPluralNames();
121: addComment("builder.plural", names);
122: for (Entry<String, String> em : datamap.entrySet()) {
123: String language = em.getKey();
124: String name = em.getValue();
125: if ((parent == null)
126: || !(name.equals(parent.getPluralName(language)))) {
127: Element elm = addContentElement("plural", name, names);
128: elm.setAttribute("xml:lang", language);
129: }
130: }
131: // descriptions
132: Element descriptions = document.createElement("descriptions");
133: addComment("builder.descriptions", root);
134: root.appendChild(descriptions);
135: // names.description
136: datamap = builder.getDescriptions();
137: addComment("builder.description", root);
138: for (Entry<String, String> em : datamap.entrySet()) {
139: String language = em.getKey();
140: String description = em.getValue();
141: if ((parent == null)
142: || !(description.equals(parent
143: .getDescription(language)))) {
144: Element elm = addContentElement("description",
145: description, descriptions);
146: elm.setAttribute("xml:lang", language);
147: }
148: }
149: // properties
150: Element properties = document.createElement("properties");
151: addComment("builder.properties", root);
152: root.appendChild(properties);
153: // properties.property
154: datamap = builder.getInitParameters();
155: for (Entry<String, String> em : datamap.entrySet()) {
156: String propname = em.getKey();
157: String propvalue = em.getValue();
158: if ((parent == null)
159: || !(propvalue.equals(parent
160: .getInitParameter(propname)))) {
161: Element elm = addContentElement("property", propvalue,
162: properties);
163: elm.setAttribute("name", propname);
164: }
165: }
166: // fieldlist
167: Element fieldlist = document.createElement("fieldlist");
168: addComment("builder.fieldlist", root);
169: root.appendChild(fieldlist);
170: // obtain all fields defined in the builder
171: List<CoreField> fields = builder
172: .getFields(NodeManager.ORDER_CREATE);
173: for (CoreField fielddef : fields) {
174: // skip otype, cannot occur in a builder xml file (doh)
175: String fieldname = fielddef.getName();
176: if (fieldname.equals("otype"))
177: continue;
178: CoreField parentField = null;
179: if (parent != null) {
180: parentField = parent.getField(fieldname);
181: }
182: // check guidata
183: Element descriptionsElm = null;
184: Map<Locale, String> descriptionsmap = fielddef
185: .getLocalizedDescription().asMap();
186: for (Entry<Locale, String> em : descriptionsmap.entrySet()) {
187: Locale locale = em.getKey();
188: String description = em.getValue();
189: if ((parentField == null)
190: || !(description.equals(parentField
191: .getDescription(locale)))) {
192: if (descriptionsElm == null)
193: descriptionsElm = document
194: .createElement("descriptions");
195: Element elm = addContentElement("description",
196: description, descriptionsElm);
197: elm.setAttribute("xml:lang", locale.toString());
198: }
199: }
200: Element guiElm = null;
201: Map<Locale, String> guinamemap = fielddef
202: .getLocalizedGUIName().asMap();
203: for (Entry<Locale, String> em : guinamemap.entrySet()) {
204: Locale locale = em.getKey();
205: String name = em.getValue();
206: if ((parentField == null)
207: || !(name
208: .equals(parentField.getGUIName(locale)))) {
209: if (guiElm == null)
210: guiElm = document.createElement("gui");
211: Element elm = addContentElement("guiname", name,
212: guiElm);
213: elm.setAttribute("xml:lang", locale.toString());
214: }
215: }
216: Element positionsElm = null;
217:
218: // positions
219: // input
220: int pos = fielddef.getEditPosition();
221: if ((parentField == null)
222: || (pos != parentField.getEditPosition())) {
223: if (positionsElm == null)
224: positionsElm = document.createElement("positions");
225: addComment("builder.field.editor.positions.input",
226: positionsElm);
227: addContentElement("input", "" + pos, positionsElm);
228: }
229: // list
230: pos = fielddef.getListPosition();
231: if ((parentField == null)
232: || (pos != parentField.getListPosition())) {
233: if (positionsElm == null)
234: positionsElm = document.createElement("positions");
235: addComment("builder.field.editor.positions.list",
236: positionsElm);
237: addContentElement("list", "" + pos, positionsElm);
238: }
239: // search
240: pos = fielddef.getSearchPosition();
241: if ((parentField == null)
242: || (pos != parentField.getSearchPosition())) {
243: if (positionsElm == null)
244: positionsElm = document.createElement("positions");
245: addComment("builder.field.editor.positions.search",
246: positionsElm);
247: addContentElement("search", "" + pos, positionsElm);
248: }
249:
250: Element dataTypeElm = null;
251: DataType dataType = fielddef.getDataType();
252: if ((parentField == null)
253: || !dataType.equals(parentField.getDataType())) {
254: dataTypeElm = (Element) document.importNode(dataType
255: .toXml(), true);
256: }
257:
258: if ((parentField == null) || (dataTypeElm != null)
259: || (descriptionsElm != null) || (guiElm != null)
260: || (positionsElm != null)) {
261: addComment("builder.field", fieldname, ""
262: + fielddef.getStoragePosition(), fieldlist);
263: Element field = document.createElement("field");
264: fieldlist.appendChild(field);
265: if (descriptionsElm != null) {
266: addComment("builder.field.descriptions", field);
267: field.appendChild(descriptionsElm);
268: }
269: if (guiElm != null) {
270: addComment("builder.field.gui", field);
271: field.appendChild(guiElm);
272: }
273: if (positionsElm != null) {
274: addComment("builder.field.editor", field);
275: Element editor = document.createElement("editor");
276: editor.appendChild(positionsElm);
277: field.appendChild(editor);
278: }
279: if (dataTypeElm != null) {
280: addComment("builder.field.datatype", field);
281: field.appendChild(dataTypeElm);
282: }
283: Element db = document.createElement("db");
284: addComment("builder.field.db", field);
285: field.appendChild(db);
286: addComment("builder.field.db.name", db);
287: addContentElement("name", fielddef.getName(), db);
288: if (parentField == null) {
289: String sType = Fields.getTypeDescription(fielddef
290: .getType());
291: addComment("builder.field.db.type", db);
292: Element dbtype = addContentElement("type", sType,
293: db);
294: String sState = Fields.getStateDescription(fielddef
295: .getState());
296: dbtype.setAttribute("state", sState);
297: int size = fielddef.getMaxLength();
298: if (size > -1) {
299: dbtype.setAttribute("size", "" + size);
300: }
301: dbtype.setAttribute("notnull", ""
302: + fielddef.isRequired());
303: dbtype
304: .setAttribute("key", ""
305: + fielddef.isUnique());
306: }
307: }
308: }
309: }
310:
311: /**
312: * Sets whether the builder will expand when writing.
313: * Expanding means that all data of a builder is written, including non-overriden data
314: * from parent builders.
315: * @param value if true, the buidler will expand
316: */
317: public void setExpandBuilder(boolean value) {
318: expandBuilder = value;
319: }
320:
321: /**
322: * Gets whether the builder will expand when writing.
323: * Expanding means that all data of a builder is written, including non-overriden data
324: * from parent builders.
325: * @return if true, the buidler will expand
326: */
327: public boolean getExpandBuilder() {
328: return expandBuilder;
329: }
330: }
|