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