View Javadoc

1   /*
2    *   Firemox is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  package net.sf.firemox.xml;
20  
21  import java.io.IOException;
22  import java.io.OutputStream;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import net.sf.firemox.clickable.ability.Optimization;
29  import net.sf.firemox.clickable.ability.Priority;
30  import net.sf.firemox.expression.intlist.ListType;
31  import net.sf.firemox.operation.IdOperation;
32  import net.sf.firemox.test.TestOn;
33  import net.sf.firemox.token.AbstractValue;
34  import net.sf.firemox.token.IdAbilities;
35  import net.sf.firemox.token.IdCardColors;
36  import net.sf.firemox.token.IdConst;
37  import net.sf.firemox.token.IdMessageBox;
38  import net.sf.firemox.token.IdPositions;
39  import net.sf.firemox.token.IdTargets;
40  import net.sf.firemox.token.IdTokens;
41  import net.sf.firemox.token.IdZones;
42  import net.sf.firemox.token.Register;
43  import net.sf.firemox.tools.MToolKit;
44  import net.sf.firemox.xml.XmlParser.Node;
45  
46  import org.apache.commons.lang.StringUtils;
47  
48  /***
49   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
50   */
51  public final class XmlTools {
52  
53  	private XmlTools() {
54  		super();
55  	}
56  
57  	private static Map<String, Integer> registerIndexName = new HashMap<String, Integer>();
58  
59  	private static Map<String, Integer> targetMode = new HashMap<String, Integer>();
60  
61  	private static Map<String, Integer> position = new HashMap<String, Integer>();
62  
63  	/***
64  	 * The available zones.
65  	 * 
66  	 * @see net.sf.firemox.xml.tbs.Tbs#buildMdb(Node, OutputStream)
67  	 */
68  	public static Map<String, Integer> zones = new HashMap<String, Integer>();
69  
70  	/***
71  	 * The available abilities
72  	 * 
73  	 * @see net.sf.firemox.xml.tbs.Tbs#buildMdb(Node, OutputStream)
74  	 */
75  	public static Map<String, Integer> abilities = new HashMap<String, Integer>();
76  
77  	private static Map<String, Integer> definedValuesName = new HashMap<String, Integer>();
78  
79  	private static Map<String, Integer> cardColorsName = new HashMap<String, Integer>();
80  
81  	/***
82  	 * If there is neither attribute neither node with the given name, '-1' is
83  	 * written instead of throwing an exception.
84  	 * 
85  	 * @param node
86  	 *          the parent node.
87  	 * @param attribute
88  	 *          the attribute/node name to write.
89  	 * @param out
90  	 *          the output stream.
91  	 * @throws IOException
92  	 *           error while writing.
93  	 */
94  	public static void tryWriteExpression(XmlParser.Node node, String attribute,
95  			OutputStream out) throws IOException {
96  		if (node.getAttribute(attribute) == null && node.get(attribute) == null) {
97  			// no such attribute --> '-1', working on the current list
98  			XmlTools.writeConstant(out, -1);
99  		} else if ("-1".equals(node.getAttribute(attribute))) {
100 			// last index --> ALL, working the last saved list
101 			XmlTools.writeConstant(out, IdConst.ALL);
102 		} else {
103 			// last index --> ALL, working an indexed saved list
104 			XmlTools.writeAttrOptions(node, attribute, out);
105 		}
106 	}
107 
108 	/***
109 	 * Fill the referenced HashMaps
110 	 */
111 	public static void initHashMaps() {
112 		clean();
113 		for (int i = IdTokens.REGISTER_INDEX_NAMES.length; i-- > 0;) {
114 			registerIndexName.put(IdTokens.REGISTER_INDEX_NAMES[i],
115 					IdTokens.REGISTER_INDEX_VALUES[i]);
116 		}
117 		for (int i = IdTargets.MODE_NAMES.length; i-- > 0;) {
118 			targetMode.put(IdTargets.MODE_NAMES[i], IdTargets.MODE_VALUES[i]);
119 		}
120 		for (int i = IdPositions.POSITION_NAMES.length; i-- > 0;) {
121 			position.put(IdPositions.POSITION_NAMES[i],
122 					IdPositions.POSITION_VALUES[i]);
123 		}
124 		for (int i = IdZones.ZONE_NAMES.length; i-- > 0;) {
125 			zones.put(IdZones.ZONE_NAMES[i], IdZones.ZONE_VALUES[i]);
126 		}
127 		for (int i = IdAbilities.ABILITIES_NAMES.length; i-- > 0;) {
128 			abilities.put(IdAbilities.ABILITIES_NAMES[i],
129 					IdAbilities.ABILITIES_VALUES[i]);
130 		}
131 		for (int i = IdConst.VALUES_NAME.length; i-- > 0;) {
132 			definedValuesName.put(IdConst.VALUES_NAME[i], IdConst.VALUES[i]);
133 		}
134 		for (int i = IdCardColors.CARD_COLOR_NAMES.length; i-- > 1;) {
135 			cardColorsName.put(IdCardColors.CARD_COLOR_NAMES[i],
136 					IdCardColors.CARD_COLOR_VALUES[i]);
137 		}
138 	}
139 
140 	/***
141 	 * Clean tables.
142 	 */
143 	public static void clean() {
144 		registerIndexName.clear();
145 		targetMode.clear();
146 		position.clear();
147 		zones.clear();
148 		abilities.clear();
149 		definedValuesName.clear();
150 		cardColorsName.clear();
151 		aliasMap = null;
152 		XmlTest.clean();
153 		XmlAction.clean();
154 		XmlExpression.clean();
155 		XmlTbs.clean();
156 		XmlModifier.clean();
157 	}
158 
159 	/***
160 	 * Write the TestOn instance corresponding to the given XSD attribute name.
161 	 * 
162 	 * @param out
163 	 *          the stream this enumeration would be written.
164 	 * @param xsdName
165 	 *          the XSD name of this TestOn.
166 	 * @throws IOException
167 	 *           error while writing.
168 	 */
169 	public static void writeTestOn(OutputStream out, String xsdName)
170 			throws IOException {
171 		if (xsdName != null) {
172 			try {
173 				TestOn.serialize(out, xsdName);
174 			} catch (IllegalArgumentException e) {
175 				XmlConfiguration.error(e.getMessage());
176 				TestOn.THIS.serialize(out);
177 			}
178 		} else if (defaultOnMeTag)
179 			TestOn.THIS.serialize(out);
180 		else
181 			TestOn.TESTED.serialize(out);
182 	}
183 
184 	/***
185 	 * @param attribute
186 	 *          the optimization name.
187 	 * @return the optimization id.
188 	 */
189 	public static Optimization getOptimization(String attribute) {
190 		if (attribute == null)
191 			return net.sf.firemox.clickable.ability.Optimization.none;
192 		return Optimization.valueOf(attribute);
193 	}
194 
195 	/***
196 	 * Return the operation code
197 	 * 
198 	 * @param operation
199 	 *          the alias
200 	 * @return the operation code
201 	 * @see net.sf.firemox.action.ModifyRegister
202 	 */
203 	public static IdOperation getOperation(String operation) {
204 		if (operation == null) {
205 			return IdOperation.ANY;
206 		}
207 		final IdOperation op = IdOperation.valueOfXsd(operation);
208 		if (op != null) {
209 			return op;
210 		}
211 		XmlConfiguration.error("Unknown operation : '" + operation + "'");
212 		return IdOperation.ANY;
213 	}
214 
215 	/***
216 	 * Return the resolution code
217 	 * 
218 	 * @param resolution
219 	 *          the alias
220 	 * @return the resolution code
221 	 */
222 	public static Priority getPriority(String resolution) {
223 		if (resolution == null)
224 			return net.sf.firemox.clickable.ability.Priority.normal;
225 		return net.sf.firemox.clickable.ability.Priority.valueOf(resolution);
226 	}
227 
228 	/***
229 	 * Return the corresponding code to the specified target mode.
230 	 * 
231 	 * @param modeAlias
232 	 *          the alias of mode
233 	 * @return the corresponding code to the specified target mode.
234 	 * @see IdTargets#MODE_NAMES
235 	 */
236 	public static int getTargetMode(String modeAlias) {
237 		if (modeAlias == null) {
238 			return IdTargets.CHOOSE;
239 		}
240 		final Integer obj = XmlTools.targetMode.get(modeAlias);
241 		if (obj != null) {
242 			return obj.intValue();
243 		}
244 		XmlConfiguration.error("Unknown target mode : '" + modeAlias + "'");
245 		return 0;
246 	}
247 
248 	/***
249 	 * Return the corresponding code to the specified position name.
250 	 * 
251 	 * @param positionAlias
252 	 *          the alias of place
253 	 * @return the corresponding code to the specified position name.
254 	 * @see IdPositions#POSITION_NAMES
255 	 */
256 	public static Integer getPosition(String positionAlias) {
257 		if (positionAlias == null) {
258 			return IdPositions.ON_THE_TOP;
259 		}
260 		return XmlTools.position.get(positionAlias);
261 	}
262 
263 	/***
264 	 * Return the corresponding code to the specified zone name.
265 	 * 
266 	 * @param zoneAlias
267 	 *          the alias of place
268 	 * @return the corresponding code to the specified zone name.
269 	 * @see IdZones#ZONE_NAMES
270 	 */
271 	public static int getZone(String zoneAlias) {
272 		final Integer obj = XmlTools.zones.get(zoneAlias);
273 		if (obj != null) {
274 			return obj.intValue();
275 		}
276 		XmlConfiguration.error("Unknown zone : '" + zoneAlias + "'");
277 		return 0;
278 	}
279 
280 	/***
281 	 * Return the corresponding code to the specified ability name.
282 	 * 
283 	 * @param abilityAlias
284 	 *          the alias of place
285 	 * @return the corresponding code to the specified ability name.
286 	 * @see IdAbilities#ABILITIES_NAMES
287 	 */
288 	public static int getAbility(String abilityAlias) {
289 		final Integer obj = XmlTools.abilities.get(abilityAlias);
290 		if (obj != null) {
291 			return obj.intValue();
292 		}
293 		XmlConfiguration.error("Unknown ability : '" + abilityAlias + "'");
294 		return 0;
295 	}
296 
297 	/***
298 	 * Return the corresponding codeto the specified string register index.
299 	 * 
300 	 * @param alias
301 	 *          the alias of value in it's string form
302 	 * @return the corresponding code to the specified string register index.
303 	 */
304 	public static int getValue(String alias) {
305 		final Integer value = getIntPriv(alias);
306 		if (value == null) {
307 			Integer obj = XmlTools.definedValuesName.get(alias);
308 			if (obj != null) {
309 				return obj.intValue();
310 			}
311 			obj = XmlTools.registerIndexName.get(alias);
312 			if (obj != null) {
313 				return obj.intValue();
314 			}
315 			// Thread.dumpStack();
316 			XmlConfiguration.error("Unknown alias : '" + alias + "'");
317 			return 0;
318 		}
319 		return value;
320 	}
321 
322 	/***
323 	 * Return the corresponding code to the specified alias.
324 	 * 
325 	 * @param alias
326 	 *          the alias of value in it's string form
327 	 * @return the corresponding code to the specified alias.
328 	 */
329 	private static Integer getIntPriv(String alias) {
330 		if (alias == null) {
331 			XmlConfiguration.error("Null register/index.", true);
332 			return 0;
333 		}
334 
335 		if (alias.length() > 0) {
336 			switch (alias.charAt(0)) {
337 			case '-':
338 				final int valueNeg = MToolKit.parseInt(alias);
339 				if (valueNeg == Integer.MIN_VALUE) {
340 					// alias not found
341 					return null;
342 				}
343 				return getNegativeConstant(valueNeg);
344 			case '1':
345 			case '2':
346 			case '3':
347 			case '4':
348 			case '5':
349 			case '6':
350 			case '7':
351 			case '8':
352 			case '9':
353 			case '0':
354 				final int value = MToolKit.parseInt(alias);
355 				if (value == Integer.MIN_VALUE) {
356 					// alias not found
357 					return null;
358 				}
359 				return value;
360 			default:
361 				// not managed number
362 			}
363 		}
364 		// it's an alias
365 		final Integer value = aliasMap.get(alias);
366 		if (value != null)
367 			return getNegativeConstant(value);
368 		return XmlTools.registerIndexName.get(alias);
369 	}
370 
371 	private static int getNegativeConstant(int value) {
372 		if (value < 0) {
373 			if (value < -127) {
374 				throw new InternalError("Negative number cannot exceed -127 : " + value);
375 			}
376 			return IdConst.NEGATIVE_NUMBER_MASK | -value;
377 		}
378 		return value;
379 	}
380 
381 	/***
382 	 * Return the corresponding code to the specified alias.
383 	 * 
384 	 * @param alias
385 	 *          the alias of value in it's string form
386 	 * @return the corresponding code to the specified alias.
387 	 */
388 	public static int getInt(String alias) {
389 		Integer value = getValue(alias);
390 		if (value == null) {
391 			XmlConfiguration.error("Unknown integer value : " + alias);
392 			return 0;
393 		}
394 		return value;
395 	}
396 
397 	/***
398 	 * Return the corresponding code to the card color name
399 	 * 
400 	 * @param alias
401 	 *          the alias name.
402 	 * @return the alias value
403 	 */
404 	public static int getAliasValue(String alias) {
405 		int value = aliasMap.get(alias);
406 		if (value == Integer.MIN_VALUE) {
407 			// alias not found
408 			value = 0;
409 			XmlConfiguration.error("Unknown alias value '" + alias + "'");
410 		}
411 		return value;
412 	}
413 
414 	/***
415 	 * Return the corresponding code to the card color name
416 	 * 
417 	 * @param colorName
418 	 *          the color alias
419 	 * @return the corresponding code to the card color name
420 	 */
421 	public static int getColor(String colorName) {
422 		final Integer obj = XmlTools.cardColorsName.get(colorName);
423 		if (obj != null) {
424 			return obj.intValue();
425 		}
426 		XmlConfiguration.error("Unknown color : '" + colorName + "'");
427 		return 0;
428 	}
429 
430 	/***
431 	 * Return the corresponding code to the card type name
432 	 * 
433 	 * @param idCard
434 	 *          the card type name
435 	 * @return the corresponding code to the card type name
436 	 */
437 	public static int getIdCard(String idCard) {
438 		final Integer value = aliasMap.get(idCard);
439 		if (value == null || value == Integer.MIN_VALUE) {
440 			// alias not found
441 			XmlConfiguration.error("Unknown idcard : '" + idCard + "'");
442 			return 0;
443 		}
444 		return value;
445 	}
446 
447 	/***
448 	 * Return the corresponding code to the list of card type name
449 	 * 
450 	 * @param list
451 	 *          is the list of card type name
452 	 * @return the corresponding code to the list of card type name.
453 	 */
454 	public static int getIdCards(String list) {
455 		// card type
456 		int idCard = 0;
457 		final String[] arrayid = list.split(" ");
458 		for (String id : arrayid) {
459 			idCard |= XmlTools.getIdCard(id);
460 		}
461 		return idCard;
462 	}
463 
464 	/***
465 	 * Write to the specified output stream the values defined as linear list ' '
466 	 * separated values, or 'value' elements.
467 	 * 
468 	 * @param out
469 	 *          output stream where the card structure will be saved
470 	 * @param node
471 	 *          the XML test container structure
472 	 * @param tagAttr
473 	 * @throws IOException
474 	 *           error while writing.
475 	 */
476 	public static void writeList(OutputStream out, XmlParser.Node node,
477 			String tagAttr) throws IOException {
478 		if (node == null) {
479 			out.write(ListType.COLLECTION.ordinal());
480 			out.write(0);
481 			return;
482 		}
483 		final String listName;
484 		if (tagAttr.endsWith("y")) {
485 			listName = tagAttr + "ies";
486 		} else {
487 			listName = tagAttr + "s";
488 		}
489 		final String nodeAttr = node.getAttribute(listName);
490 		if (nodeAttr != null) {
491 			// TODO Support the java list and reference value
492 
493 			// the value is directly specified : linear list / range
494 			final String[] values;
495 			if (nodeAttr.indexOf("..") != -1) {
496 				out.write(ListType.RANGE.ordinal());
497 				values = nodeAttr.split("//.//.");
498 			} else {
499 				out.write(ListType.COLLECTION.ordinal());
500 				values = nodeAttr.split(" ");
501 			}
502 			out.write(values.length);
503 			for (String value : values) {
504 				writeSimpleValue(out, value);
505 			}
506 		} else {
507 			// the value is defined if an inner-element, it's a complex value
508 			out.write(ListType.COLLECTION.ordinal());
509 			Node valuesNode = node.get(listName);
510 			if (valuesNode == null) {
511 				out.write(0);
512 			} else {
513 				final List<Node> values = valuesNode.getNodes("value");
514 				out.write(values.size());
515 				for (XmlParser.Node value : values) {
516 					writeComplexValue(out, value);
517 				}
518 			}
519 		}
520 	}
521 
522 	/***
523 	 * Write to the specified output stream the 16bits integer value.
524 	 * 
525 	 * @param out
526 	 *          output stream where the card structure will be saved
527 	 * @param value
528 	 *          the simple value to write.
529 	 * @throws IOException
530 	 *           error while writing.
531 	 */
532 	public static void writeSimpleValue(OutputStream out, String value)
533 			throws IOException {
534 		final AbstractValue abstractValue = AbstractValue.valueOfXsd(value);
535 		if (abstractValue != null) {
536 			IdOperation.ABSTRACT_VALUE.serialize(out);
537 			abstractValue.serialize(out);
538 		} else {
539 			TestOn testOn = TestOn.valueOfXsd(value);
540 			if (testOn != null) {
541 				IdOperation.TEST_ON.serialize(out);
542 				testOn.serialize(out);
543 			} else {
544 				Integer intValue = getIntPriv(value);
545 				if (intValue == null) {
546 					XmlConfiguration.error("Unknown alias : '" + value + "'");
547 					writeConstant(out, 0);
548 				} else {
549 					writeConstant(out, intValue);
550 				}
551 			}
552 		}
553 	}
554 
555 	/***
556 	 * Write to the specified output stream the 16bits integer value.
557 	 * 
558 	 * @param out
559 	 *          output stream where the card structure will be saved
560 	 * @param value
561 	 *          the simple value to write.
562 	 * @throws IOException
563 	 *           error while writing.
564 	 */
565 	public static void writeConstant(OutputStream out, int value)
566 			throws IOException {
567 		IdOperation.INT_VALUE.serialize(out);
568 		MToolKit.writeInt16(out, getNegativeConstant(value));
569 	}
570 
571 	/***
572 	 * @param out
573 	 *          output stream where the card structure will be saved
574 	 * @param expr
575 	 *          complex expression node to write
576 	 * @throws IOException
577 	 *           error while writing.
578 	 */
579 	public static void writeComplexValue(OutputStream out, XmlParser.Node expr)
580 			throws IOException {
581 		// try getting the value as register access : register name + index
582 		String register = expr.getAttribute("register");
583 		if (register != null) {
584 			if ("true".equals(expr.getAttribute("base"))) {
585 				IdOperation.BASE_REGISTER_INT_VALUE.serialize(out);
586 			} else {
587 				IdOperation.REGISTER_ACCESS.serialize(out);
588 			}
589 			Register.valueOfXsd(register).serialize(out);
590 			writeAttrOptions(expr, "index", out);
591 		} else {
592 			// this is a complex expression : add, minus, method, counter, ...
593 			final Iterator<?> it = expr.iterator();
594 			while (it.hasNext()) {
595 				Object obj = it.next();
596 				if (obj instanceof XmlParser.Node) {
597 					XmlExpression.getExpression(((XmlParser.Node) obj).getTag())
598 							.buildMdb((XmlParser.Node) obj, out);
599 					return;
600 				}
601 			}
602 			XmlConfiguration
603 					.error("Element '"
604 							+ expr.getParent().getTag()
605 							+ "' must contain a complex operation, or have value defined as attribute. Context="
606 							+ expr.getParent());
607 		}
608 
609 	}
610 
611 	/***
612 	 * @param node
613 	 *          the XML test container structure
614 	 * @param tagAttr
615 	 * @param out
616 	 *          output stream where the card structure will be saved
617 	 * @throws IOException
618 	 *           error while writing.
619 	 */
620 	public static void writeAttrOptions(XmlParser.Node node, String tagAttr,
621 			OutputStream out) throws IOException {
622 		writeAttrOptionsDefault(node, tagAttr, out, null);
623 	}
624 
625 	/***
626 	 * @param node
627 	 *          the XML test container structure
628 	 * @param tagAttr
629 	 * @param out
630 	 *          output stream where the card structure will be saved
631 	 * @param defaultValue
632 	 *          the default value to use if neither attribute, neither element has
633 	 *          been found.
634 	 * @throws IOException
635 	 *           error while writing.
636 	 */
637 	public static void writeAttrOptionsDefault(XmlParser.Node node,
638 			String tagAttr, OutputStream out, String defaultValue) throws IOException {
639 		if (defaultValue != null && node.getAttribute(tagAttr) == null
640 				&& node.get(tagAttr) == null) {
641 			node.addAttribute(new XmlParser.Attribute(tagAttr, defaultValue));
642 		}
643 		final String nodeAttr = node.getAttribute(tagAttr);
644 		if (nodeAttr != null) {
645 			// the value is directly specified : simple integer or register access
646 			if (node.getAttribute(tagAttr + "-class") != null
647 					&& !int.class.getName().equals(node.getAttribute(tagAttr + "-class"))
648 					&& !Integer.class.getName().equals(
649 							node.getAttribute(tagAttr + "-class"))) {
650 				// No integer expression
651 				IdOperation.OBJECT_VALUE.serialize(out);
652 				MToolKit.writeString(out, node.getAttribute(tagAttr + "-class"));
653 				MToolKit.writeString(out, node.getAttribute(tagAttr));
654 			} else if (nodeAttr.startsWith("%")) {
655 				// This is reference value
656 				IdOperation.REF_VALUE.serialize(out);
657 				MToolKit.writeString(out, nodeAttr);
658 			} else {
659 				writeSimpleValue(out, nodeAttr);
660 			}
661 		} else {
662 			// the value is defined if an inner-element, it's a complex value
663 			final XmlParser.Node expr = node.get(tagAttr);
664 			if (expr == null) {
665 				XmlConfiguration.error("Neither element '" + tagAttr
666 						+ "' neither attribute '" + tagAttr
667 						+ "' have been found in element '" + node.getTag()
668 						+ "'.\n\t Context:\n" + node);
669 				return;
670 			}
671 			writeComplexValue(out, expr);
672 		}
673 	}
674 
675 	/***
676 	 * @param node
677 	 * @param tagAttr
678 	 * @param out
679 	 * @param nameSpace
680 	 * @throws IOException
681 	 *           error while writing.
682 	 */
683 	public static void writeAttrOptions(XmlParser.Node node, String tagAttr,
684 			OutputStream out, String nameSpace) throws IOException {
685 		final String colorAttr = node.getAttribute(tagAttr);
686 		if (colorAttr != null) {
687 			final String method = "get" + StringUtils.capitalize(nameSpace);
688 			try {
689 				final Integer retVal = (Integer) XmlTools.class.getMethod(method,
690 						String.class).invoke(null, colorAttr);
691 				if (retVal == null) {
692 					XmlConfiguration.error("Unknown " + nameSpace + " : '" + colorAttr
693 							+ "'");
694 					writeConstant(out, 0);
695 				} else {
696 					writeConstant(out, retVal);
697 				}
698 			} catch (Throwable e2) {
699 				XmlConfiguration.error("Error found in 'get" + nameSpace + "' : "
700 						+ e2.getMessage());
701 				writeConstant(out, 0);
702 			}
703 		} else {
704 			final XmlParser.Node expr = node.get(tagAttr);
705 			if (expr == null) {
706 				XmlConfiguration.error("Neither element '" + tagAttr
707 						+ "' neither attribute '" + tagAttr
708 						+ "' have been found in element '" + node.getTag() + "'. Context="
709 						+ node);
710 				return;
711 			}
712 			writeComplexValue(out, expr);
713 		}
714 	}
715 
716 	/***
717 	 * @param attribute
718 	 *          the message name.
719 	 * @return the message id.
720 	 */
721 	public static IdMessageBox getMessageType(String attribute) {
722 		if (attribute == null) {
723 			return IdMessageBox.ok;
724 		}
725 		IdMessageBox messageBox = IdMessageBox.valueOf(attribute);
726 		if (messageBox == null) {
727 			return IdMessageBox.ok;
728 		}
729 		return messageBox;
730 	}
731 
732 	/***
733 	 * The defined user alias
734 	 */
735 	public static Map<String, Integer> aliasMap = null;
736 
737 	/***
738 	 * This field must be set by activated ability, triggered, and counters to
739 	 * known the default value for the 'on' attribute
740 	 */
741 	public static boolean defaultOnMeTag;
742 
743 	/***
744 	 * This field must be set by actions needing some pre-check test such as
745 	 * target action. When is <code>true</code>, the last build test does not
746 	 * refer to a ability's runtime register such as 'stack' register.
747 	 */
748 	public static boolean testCanBePreempted;
749 
750 	/***
751 	 * Return the named node from the given node. This node may be defined in an
752 	 * external xml file.
753 	 * 
754 	 * @param node
755 	 *          the parent node.
756 	 * @param nodeName
757 	 *          the node name.
758 	 * @return the named node from the given node.
759 	 */
760 	public static Node getExternalizableNode(Node node, String nodeName) {
761 		final Node references = node.get(nodeName);
762 		if (references.getAttribute("file") != null) {
763 			// Load the references file
764 			try {
765 				return new XmlParser(XmlConfiguration.getOptions().isXsdValidation())
766 						.parse(MToolKit.getUrl(references.getAttribute("file")).getPath());
767 			} catch (Exception e) {
768 				throw new RuntimeException(e);
769 			}
770 		}
771 		return references;
772 	}
773 }