001: /**
002: * LibreSource
003: * Copyright (C) 2004-2008 Artenum SARL / INRIA
004: * http://www.libresource.org - contact@artenum.com
005: *
006: * This file is part of the LibreSource software,
007: * which can be used and distributed under license conditions.
008: * The license conditions are provided in the LICENSE.TXT file
009: * at the root path of the packaging that enclose this file.
010: * More information can be found at
011: * - http://dev.libresource.org/home/license
012: *
013: * Initial authors :
014: *
015: * Guillaume Bort / INRIA
016: * Francois Charoy / Universite Nancy 2
017: * Julien Forest / Artenum
018: * Claude Godart / Universite Henry Poincare
019: * Florent Jouille / INRIA
020: * Sebastien Jourdain / INRIA / Artenum
021: * Yves Lerumeur / Artenum
022: * Pascal Molli / Universite Henry Poincare
023: * Gerald Oster / INRIA
024: * Mariarosa Penzi / Artenum
025: * Gerard Sookahet / Artenum
026: * Raphael Tani / INRIA
027: *
028: * Contributors :
029: *
030: * Stephane Bagnier / Artenum
031: * Amadou Dia / Artenum-IUP Blois
032: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
033: */package org.libresource.so6.core.tf;
034:
035: import fr.loria.ecoo.so6.xml.util.XmlUtil;
036:
037: import org.libresource.so6.core.WsConnection;
038: import org.libresource.so6.core.command.Command;
039: import org.libresource.so6.core.command.Id;
040: import org.libresource.so6.core.command.NoOp;
041: import org.libresource.so6.core.command.xml.DeleteAttribute;
042: import org.libresource.so6.core.command.xml.DeleteNode;
043: import org.libresource.so6.core.command.xml.InsertAttribute;
044: import org.libresource.so6.core.command.xml.InsertNode;
045: import org.libresource.so6.core.command.xml.UpdateAttribute;
046: import org.libresource.so6.core.command.xml.UpdateXmlFile;
047: import org.libresource.so6.core.engine.util.ObjectCloner;
048:
049: import java.lang.reflect.Method;
050:
051: import java.util.ArrayList;
052: import java.util.Iterator;
053: import java.util.StringTokenizer;
054:
055: /**
056: * @author Ecoo Team Loria
057: */
058: public class XmlFileFunctions {
059: private WsConnection ws;
060:
061: public XmlFileFunctions(WsConnection ws) {
062: this .ws = ws;
063: }
064:
065: public Command transp(UpdateXmlFile c1, UpdateXmlFile c2)
066: throws Exception {
067: Command res = null;
068: Method m = null;
069:
070: try {
071: // Make transformation only if needed
072: if (c1.getPath().equals(c2.getPath())) {
073: m = this .getClass().getMethod("tf",
074: new Class[] { c1.getClass(), c2.getClass() });
075: } else {
076: return c1;
077: }
078: } catch (NoSuchMethodException e1) {
079: try {
080: m = this .getClass().getMethod(
081: "tf",
082: new Class[] { c1.getClass().getSuperclass(),
083: c2.getClass() });
084: } catch (NoSuchMethodException e2) {
085: try {
086: m = this .getClass().getMethod(
087: "tf",
088: new Class[] { c1.getClass(),
089: c2.getClass().getSuperclass() });
090: } catch (NoSuchMethodException e3) {
091: m = this .getClass().getMethod(
092: "tf",
093: new Class[] {
094: c1.getClass().getSuperclass(),
095: c2.getClass().getSuperclass() });
096: }
097: }
098: }
099:
100: //System.out.println("Tf: " + c1 + "\n " + c2);
101: //System.out.println("method: "+m);
102: Command c = (Command) m.invoke(this , new Object[] { c1, c2 });
103:
104: //System.out.println("return: " + c);
105: return c;
106: }
107:
108: /*
109: * Take care of XML commands - InsertNode - DeleteNode - UpdateNode -
110: * MoveNode - InsertProcessingInstructionNode - InsertAttribute -
111: * DeleteAttribute - UpdateAttribute - SetDocumentType - InsertSubTree
112: */
113:
114: /**
115: * InsertNode
116: */
117: public Command tf(InsertNode c1, InsertNode c2) throws Exception {
118: String p1 = XmlUtil.getParentPath(c1.getNodePath());
119: String p2 = XmlUtil.getParentPath(c2.getNodePath());
120: int pos2 = getChildPos(c2.getNodePath());
121: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
122:
123: if (p1.equals(p2)) {
124: int pos1 = getChildPos(c1.getNodePath());
125:
126: if (pos1 < pos2) {
127: return c1;
128: } else if (pos1 == pos2) {
129: if (c1.getTicket() == -1) {
130: clone.setNodePath(setChildIndex(getDepth(clone
131: .getNodePath()), clone.getNodePath(),
132: getChildIndex(
133: getDepth(clone.getNodePath()),
134: clone.getNodePath()) + 1));
135:
136: return clone;
137: } else {
138: // c1 remote command
139: return c1;
140: }
141: } else { // pos1 > pos2
142: clone.setNodePath(setChildIndex(getDepth(clone
143: .getNodePath()), clone.getNodePath(),
144: getChildIndex(getDepth(clone.getNodePath()),
145: clone.getNodePath()) + 1));
146:
147: return clone;
148: }
149: } else if (subsume(c1, c2)) {
150: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
151: .getNodePath());
152:
153: if (pos2 <= pos) {
154: clone.setNodePath(setChildIndex(getDepth(c2
155: .getNodePath()), clone.getNodePath(), pos + 1));
156:
157: return clone;
158: }
159:
160: return c1;
161: } else {
162: return c1;
163: }
164: }
165:
166: public Command tf(InsertNode c1, DeleteNode c2) throws Exception {
167: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
168: int pos2 = getChildPos(c2.getNodePath());
169:
170: if (childOf(c1, c2)) {
171: return new NoOp(c1, ws);
172: } else if (subsume(c1, c2)) {
173: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
174: .getNodePath());
175:
176: if (pos2 < pos) {
177: clone.setNodePath(setChildIndex(getDepth(c2
178: .getNodePath()), clone.getNodePath(), pos - 1));
179:
180: return clone;
181: }
182: }
183:
184: return c1;
185: }
186:
187: public Command tf(InsertNode c1, InsertAttribute c2)
188: throws Exception {
189: return c1;
190: }
191:
192: public Command tf(InsertNode c1, DeleteAttribute c2)
193: throws Exception {
194: return c1;
195: }
196:
197: public Command tf(InsertNode c1, UpdateAttribute c2)
198: throws Exception {
199: return c1;
200: }
201:
202: /**
203: * DeleteNode
204: */
205: public Command tf(DeleteNode c1, InsertNode c2) throws Exception {
206: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
207: int pos2 = getChildPos(c2.getNodePath());
208:
209: if (subsume(c1, c2)) {
210: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
211: .getNodePath());
212:
213: if (pos2 <= pos) {
214: clone.setNodePath(setChildIndex(getDepth(c2
215: .getNodePath()), clone.getNodePath(), pos + 1));
216:
217: return clone;
218: }
219: }
220:
221: return c1;
222: }
223:
224: public Command tf(DeleteNode c1, DeleteNode c2) throws Exception {
225: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
226: int pos2 = getChildPos(c2.getNodePath());
227:
228: if (childOf(c1, c2)) {
229: return new NoOp(c1, ws);
230: } else if (subsume(c1, c2)) {
231: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
232: .getNodePath());
233:
234: if (pos2 < pos) {
235: clone.setNodePath(setChildIndex(getDepth(c2
236: .getNodePath()), clone.getNodePath(), pos - 1));
237:
238: return clone;
239: }
240: }
241:
242: return c1;
243: }
244:
245: public Command tf(DeleteNode c1, InsertAttribute c2)
246: throws Exception {
247: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
248: int pos2 = getChildPos(c2.getNodePath());
249:
250: if (subsume(c1, c2)) {
251: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
252: .getNodePath());
253:
254: if (pos2 <= pos) {
255: clone.setNodePath(setChildIndex(getDepth(c2
256: .getNodePath()), clone.getNodePath(), pos + 1));
257:
258: return clone;
259: }
260: }
261:
262: return c1;
263: }
264:
265: public Command tf(DeleteNode c1, DeleteAttribute c2)
266: throws Exception {
267: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
268: int pos2 = getChildPos(c2.getNodePath());
269:
270: if (subsume(c1, c2)) {
271: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
272: .getNodePath());
273:
274: if (pos2 <= pos) {
275: clone.setNodePath(setChildIndex(getDepth(c2
276: .getNodePath()), clone.getNodePath(), pos + 1));
277:
278: return clone;
279: }
280: }
281:
282: return c1;
283: }
284:
285: public Command tf(DeleteNode c1, UpdateAttribute c2)
286: throws Exception {
287: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
288: int pos2 = getChildPos(c2.getNodePath());
289:
290: if (subsume(c1, c2)) {
291: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
292: .getNodePath());
293:
294: if (pos2 <= pos) {
295: clone.setNodePath(setChildIndex(getDepth(c2
296: .getNodePath()), clone.getNodePath(), pos + 1));
297:
298: return clone;
299: }
300: }
301:
302: return c1;
303: }
304:
305: /**
306: * InsertAttribute
307: */
308: public Command tf(InsertAttribute c1, InsertNode c2)
309: throws Exception {
310: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
311: int pos2 = getChildPos(c2.getNodePath());
312:
313: if (subsume(c1, c2)) {
314: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
315: .getNodePath());
316:
317: if (pos2 <= pos) {
318: clone.setNodePath(setChildIndex(getDepth(c2
319: .getNodePath()), clone.getNodePath(), pos + 1));
320:
321: return clone;
322: }
323: }
324:
325: return c1;
326: }
327:
328: public Command tf(InsertAttribute c1, DeleteNode c2)
329: throws Exception {
330: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
331: int pos2 = getChildPos(c2.getNodePath());
332:
333: if (childOf(c1, c2)) {
334: return new NoOp(c1, ws);
335: } else if (subsume(c1, c2)) {
336: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
337: .getNodePath());
338:
339: if (pos2 < pos) {
340: clone.setNodePath(setChildIndex(getDepth(c2
341: .getNodePath()), clone.getNodePath(), pos - 1));
342:
343: return clone;
344: }
345: }
346:
347: return c1;
348: }
349:
350: public Command tf(InsertAttribute c1, InsertAttribute c2)
351: throws Exception {
352: if (c1.getNodePath().equals(c2.getNodePath())
353: && c1.getAttributeName().equals(c2.getAttributeName())) {
354: if (c1.getAttributeValue().equals(c2.getAttributeValue())) {
355: return new Id(c1, ws);
356: } else {
357: //InsertAttribute clone = (InsertAttribute)
358: // ObjectCloner.deepCopy(c1);
359: String newvalue = null;
360: UpdateAttribute clone = new UpdateAttribute(c1
361: .getTicket(), c1.getPath(), c1.getWsName(), c1
362: .getTime(), c1.getNodePath(), c1
363: .getAttributeName(), c1.getAttributeValue(),
364: newvalue);
365:
366: if (c1.getTicket() == -1) {
367: newvalue = c2.getAttributeValue() + "|"
368: + c1.getAttributeValue();
369: } else {
370: newvalue = c1.getAttributeValue() + "|"
371: + c2.getAttributeValue();
372: }
373:
374: clone.setNewValue(newvalue);
375:
376: //clone.setAttributeValue(newvalue);
377: return clone;
378: }
379: } else {
380: return c1;
381: }
382: }
383:
384: public Command tf(InsertAttribute c1, DeleteAttribute c2)
385: throws Exception {
386: return c1;
387: }
388:
389: public Command tf(InsertAttribute c1, UpdateAttribute c2)
390: throws Exception {
391: return c1;
392: }
393:
394: /**
395: * DeleteAttribute
396: */
397: public Command tf(DeleteAttribute c1, InsertNode c2)
398: throws Exception {
399: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
400: int pos2 = getChildPos(c2.getNodePath());
401:
402: if (subsume(c1, c2)) {
403: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
404: .getNodePath());
405:
406: if (pos2 <= pos) {
407: clone.setNodePath(setChildIndex(getDepth(c2
408: .getNodePath()), clone.getNodePath(), pos + 1));
409:
410: return clone;
411: }
412: }
413:
414: return c1;
415: }
416:
417: public Command tf(DeleteAttribute c1, DeleteNode c2)
418: throws Exception {
419: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
420: int pos2 = getChildPos(c2.getNodePath());
421:
422: if (childOf(c1, c2)) {
423: return new NoOp(c1, ws);
424: } else if (subsume(c1, c2)) {
425: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
426: .getNodePath());
427:
428: if (pos2 < pos) {
429: clone.setNodePath(setChildIndex(getDepth(c2
430: .getNodePath()), clone.getNodePath(), pos - 1));
431:
432: return clone;
433: }
434: }
435:
436: return c1;
437: }
438:
439: public Command tf(DeleteAttribute c1, InsertAttribute c2)
440: throws Exception {
441: return c1;
442: }
443:
444: public Command tf(DeleteAttribute c1, DeleteAttribute c2)
445: throws Exception {
446: if (c1.getNodePath().equals(c2.getNodePath())
447: && c1.getAttributeName().equals(c2.getAttributeName())) {
448: return new Id(c1, ws);
449: } else {
450: return c1;
451: }
452: }
453:
454: public Command tf(DeleteAttribute c1, UpdateAttribute c2)
455: throws Exception {
456: return c1;
457: }
458:
459: /**
460: * UpdateAttribute
461: */
462: public Command tf(UpdateAttribute c1, InsertNode c2)
463: throws Exception {
464: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
465: int pos2 = getChildPos(c2.getNodePath());
466:
467: if (subsume(c1, c2)) {
468: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
469: .getNodePath());
470:
471: if (pos2 <= pos) {
472: clone.setNodePath(setChildIndex(getDepth(c2
473: .getNodePath()), clone.getNodePath(), pos + 1));
474:
475: return clone;
476: }
477: }
478:
479: return c1;
480: }
481:
482: public Command tf(UpdateAttribute c1, DeleteNode c2)
483: throws Exception {
484: UpdateXmlFile clone = (UpdateXmlFile) ObjectCloner.deepCopy(c1);
485: int pos2 = getChildPos(c2.getNodePath());
486:
487: if (childOf(c1, c2)) {
488: return new NoOp(c1, ws);
489: } else if (subsume(c1, c2)) {
490: int pos = getChildIndex(getDepth(c2.getNodePath()), clone
491: .getNodePath());
492:
493: if (pos2 < pos) {
494: clone.setNodePath(setChildIndex(getDepth(c2
495: .getNodePath()), clone.getNodePath(), pos - 1));
496:
497: return clone;
498: }
499: }
500:
501: return c1;
502: }
503:
504: public Command tf(UpdateAttribute c1, InsertAttribute c2)
505: throws Exception {
506: return c1;
507: }
508:
509: public Command tf(UpdateAttribute c1, DeleteAttribute c2)
510: throws Exception {
511: if (c1.getNodePath().equals(c2.getNodePath())
512: && c1.getAttributeName().equals(c2.getAttributeName())) {
513: return new NoOp(c1, ws);
514: } else {
515: return c1;
516: }
517: }
518:
519: public Command tf(UpdateAttribute c1, UpdateAttribute c2)
520: throws Exception {
521: if (c1.getNodePath().equals(c2.getNodePath())
522: && c1.getAttributeName().equals(c2.getAttributeName())) {
523: if (c1.getNewValue().equals(c2.getNewValue())) {
524: return new Id(c1, ws);
525: } else {
526: UpdateAttribute clone = (UpdateAttribute) ObjectCloner
527: .deepCopy(c1);
528: String newvalue;
529:
530: // peut etre qu'on devrait mettre a jour la oldvalue aussi ???
531: if (c1.getTicket() == -1) {
532: newvalue = c2.getNewValue() + "|"
533: + c1.getNewValue();
534: } else {
535: newvalue = c1.getNewValue() + "|"
536: + c2.getNewValue();
537: }
538:
539: clone.setNewValue(newvalue);
540:
541: return clone;
542: }
543: } else {
544: return c1;
545: }
546: }
547:
548: /**
549: * XML Util
550: */
551: public boolean childOf(UpdateXmlFile c1, UpdateXmlFile c2) {
552: return c1.getNodePath().startsWith(c2.getNodePath());
553: }
554:
555: // le path de C1 est subsum? par le path de C2
556: // parent de C2 est un prefix du parent de C1
557: public boolean subsume(UpdateXmlFile c1, UpdateXmlFile c2) {
558: String c1Path = XmlUtil.getParentPath(c1.getNodePath());
559: String c2ParentPath = XmlUtil.getParentPath(c2.getNodePath());
560:
561: //System.out.println("c1:" + c1.getNodePath());
562: //System.out.println("c2:" + c2.getNodePath());
563: //System.out.println("subsume(c1,c2) [c2 plus petit c1]:" +
564: // c1Path.startsWith(c2ParentPath));
565: return c1Path.startsWith(c2ParentPath);
566: }
567:
568: public int getChildPos(String path) {
569: int index = path.lastIndexOf(":");
570:
571: if (index == -1) {
572: return Integer.parseInt(path);
573: }
574:
575: return Integer.parseInt(path.substring(index + 1));
576: }
577:
578: public int getChildIndex(int depth, String path) {
579: // add for report
580: if (path.lastIndexOf(":") == -1) {
581: return new Integer(path).intValue();
582: }
583:
584: //
585: return Integer.parseInt((String) convertPath(path).get(depth));
586: }
587:
588: public String setChildIndex(int depth, String path,
589: int newChildIndex) {
590: ArrayList result = convertPath(path);
591:
592: // add for report
593: if (result.size() == 1) {
594: return "0";
595: }
596:
597: //
598: result.set(depth, "" + newChildIndex);
599:
600: return convertPath(result);
601: }
602:
603: public int getDepth(String path) {
604: return convertPath(path).size() - 1;
605: }
606:
607: public String convertPath(ArrayList path) {
608: StringBuffer buf = new StringBuffer();
609:
610: for (Iterator i = path.iterator(); i.hasNext();) {
611: buf.append(i.next());
612:
613: if (i.hasNext()) {
614: buf.append(":");
615: }
616: }
617:
618: return buf.toString();
619: }
620:
621: public ArrayList convertPath(String path) {
622: ArrayList result = new ArrayList();
623: StringTokenizer st = new StringTokenizer(path, ":");
624:
625: while (st.hasMoreTokens()) {
626: result.add(st.nextToken());
627: }
628:
629: return result;
630: }
631:
632: public String[] cutHead(String nodePath) {
633: StringBuffer buffer = new StringBuffer();
634: buffer.append(nodePath.substring(0, nodePath.indexOf(":")));
635: buffer.append(" ");
636: buffer.append(nodePath.substring(nodePath.indexOf(":") + 1));
637:
638: return buffer.toString().split(" ");
639: }
640:
641: public String incHeadPos(String nodePath) {
642: String[] path = cutHead(nodePath);
643:
644: return (Integer.parseInt(path[0]) + 1) + path[1];
645: }
646:
647: public String decHeadPos(String nodePath) {
648: String[] path = cutHead(nodePath);
649:
650: return (Integer.parseInt(path[0]) - 1) + path[1];
651: }
652: }
|