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 org.libresource.so6.core.WsConnection;
036: import org.libresource.so6.core.command.Command;
037: import org.libresource.so6.core.command.Id;
038: import org.libresource.so6.core.command.Macro;
039: import org.libresource.so6.core.command.NoOp;
040: import org.libresource.so6.core.command.UpdateFile;
041: import org.libresource.so6.core.command.fs.AddBinaryFile;
042: import org.libresource.so6.core.command.fs.AddDir;
043: import org.libresource.so6.core.command.fs.AddFile;
044: import org.libresource.so6.core.command.fs.FsCommand;
045: import org.libresource.so6.core.command.fs.Remove;
046: import org.libresource.so6.core.command.fs.Rename;
047: import org.libresource.so6.core.command.fs.UpdateBinaryFile;
048: import org.libresource.so6.core.engine.util.FileUtils;
049: import org.libresource.so6.core.engine.util.ObjectCloner;
050:
051: import java.io.File;
052:
053: import java.lang.reflect.Method;
054:
055: /**
056: * @author Ecoo Team Loria
057: */
058: public class FileSystemFunctions {
059: private WsConnection ws;
060:
061: public FileSystemFunctions(WsConnection ws) {
062: this .ws = ws;
063: }
064:
065: public Command transp(Command c1, FsCommand c2) throws Exception {
066: Command res = null;
067: Method m = null;
068:
069: try {
070: //System.out.println("FS: " + c1.getClass() + " - " +
071: // c2.getClass());
072: m = this .getClass().getMethod("tf",
073: new Class[] { c1.getClass(), c2.getClass() });
074: } catch (NoSuchMethodException e1) {
075: if ((c2 instanceof Remove) || (c2 instanceof Rename)) {
076: try {
077: m = this .getClass().getMethod(
078: "tf",
079: new Class[] {
080: c1.getClass().getSuperclass(),
081: c2.getClass() });
082: } catch (NoSuchMethodException e2) {
083: m = this .getClass().getMethod(
084: "tf",
085: new Class[] {
086: c1.getClass().getSuperclass()
087: .getSuperclass(),
088: c2.getClass() });
089: }
090: } else {
091: try {
092: m = this .getClass().getMethod(
093: "tf",
094: new Class[] {
095: c1.getClass().getSuperclass(),
096: c2.getClass() });
097: } catch (NoSuchMethodException e2) {
098: try {
099: m = this
100: .getClass()
101: .getMethod(
102: "tf",
103: new Class[] {
104: c1.getClass(),
105: c2
106: .getClass()
107: .getSuperclass() });
108: } catch (NoSuchMethodException e3) {
109: m = this
110: .getClass()
111: .getMethod(
112: "tf",
113: new Class[] {
114: c1
115: .getClass()
116: .getSuperclass(),
117: c2
118: .getClass()
119: .getSuperclass() });
120: }
121: }
122: }
123: }
124:
125: return (Command) m.invoke(this , new Object[] { c1, c2 });
126: }
127:
128: /*
129: * Take care of FileSystem commands - AddFile - AddDir - Remove - Rename -
130: * UpdateBinaryFile
131: */
132:
133: /**
134: * AddFile
135: */
136: public Command tf(AddFile c1, AddFile c2) throws Exception {
137: if (c1.getPath().equals(c2.getPath())) {
138: if (c1.getTicket() == -1) {
139: Command cr = (Command) ObjectCloner.deepCopy(c1);
140: cr.setPath(uniquePath(c1, c2));
141: cr.setConflict(true);
142:
143: return cr;
144: } else {
145: Macro m = new Macro(c1, ws);
146: m.setCommand(new Rename(c1.getPath(), ws, uniquePath(
147: c1, c2)), 1);
148: m.setCommand(c1, 2);
149: c1.setConflict(true);
150:
151: return m;
152: }
153: }
154:
155: return c1;
156: }
157:
158: public Command tf(AddFile c1, AddDir c2) throws Exception {
159: if (c1.getPath().equals(c2.getPath())) {
160: if (c1.getTicket() == -1) {
161: Command cr = (Command) ObjectCloner.deepCopy(c1);
162: cr.setPath(uniquePath(c1, c2));
163: cr.setConflict(true);
164:
165: return cr;
166: } else {
167: Macro m = new Macro(c1, ws);
168: m.setCommand(new Rename(c1.getPath(), ws, uniquePath(
169: c1, c2)), 1);
170: m.setCommand(c1, 2);
171: c1.setConflict(true);
172:
173: return m;
174: }
175: }
176:
177: return c1;
178: }
179:
180: public Command tf(AddFile c1, Remove c2) throws Exception {
181: if (childOf(c1, c2)) {
182: return new NoOp(c1, ws);
183: }
184:
185: return c1;
186: }
187:
188: public Command tf(AddFile c1, Rename c2) throws Exception {
189: if (childOf(c1, c2)) {
190: Command cr = (Command) ObjectCloner.deepCopy(c1);
191: cr.setPath(replacePath(c1.getPath(), c2.getNewPath()));
192:
193: return cr;
194: }
195:
196: return c1;
197: }
198:
199: public Command tf(AddFile c1, UpdateBinaryFile c2) throws Exception {
200: return c1;
201: }
202:
203: /**
204: * AddDir
205: */
206: public Command tf(AddDir c1, AddFile c2) throws Exception {
207: if (c1.getPath().equals(c2.getPath())) {
208: if (c1.getTicket() == -1) {
209: Command cr = (Command) ObjectCloner.deepCopy(c1);
210: cr.setPath(uniquePath(c1, c2));
211: cr.setConflict(true);
212:
213: return cr;
214: } else {
215: Macro m = new Macro(c1, ws);
216: m.setCommand(new Rename(c1.getPath(), ws, uniquePath(
217: c1, c2)), 1);
218: m.setCommand(c1, 2);
219: c1.setConflict(true);
220:
221: return m;
222: }
223: }
224:
225: return c1;
226: }
227:
228: public Command tf(AddDir c1, AddDir c2) throws Exception {
229: if (c1.getPath().equals(c2.getPath())) {
230: if (c1.getTicket() == -1) {
231: Command cr = (Command) ObjectCloner.deepCopy(c1);
232: cr.setPath(uniquePath(c1, c2));
233: cr.setConflict(true);
234:
235: return cr;
236: } else {
237: Macro m = new Macro(c1, ws);
238: m.setCommand(new Rename(c1.getPath(), ws, uniquePath(
239: c1, c2)), 1);
240: m.setCommand(c1, 2);
241: c1.setConflict(true);
242:
243: return m;
244: }
245: }
246:
247: return c1;
248: }
249:
250: public Command tf(AddDir c1, Remove c2) throws Exception {
251: if (childOf(c1, c2)) {
252: return new NoOp(c1, ws);
253: }
254:
255: return c1;
256: }
257:
258: public Command tf(AddDir c1, Rename c2) throws Exception {
259: if (childOf(c1, c2)) {
260: Command cr = (Command) ObjectCloner.deepCopy(c1);
261: cr.setPath(replacePath(c1.getPath(), c2.getNewPath()));
262:
263: return cr;
264: }
265:
266: return c1;
267: }
268:
269: public Command tf(AddDir c1, UpdateBinaryFile c2) throws Exception {
270: return c1;
271: }
272:
273: /**
274: * Remove
275: */
276: public Command tf(Remove c1, AddFile c2) throws Exception {
277: return c1;
278: }
279:
280: public Command tf(Remove c1, AddDir c2) throws Exception {
281: return c1;
282: }
283:
284: public Command tf(Remove c1, Remove c2) throws Exception {
285: if (c1.getPath().equals(c2.getPath())) {
286: return new Id(c1, ws);
287: } else if (childOf(c1, c2)) {
288: return new NoOp(c1, ws);
289: }
290:
291: return c1;
292: }
293:
294: public Command tf(Remove c1, Rename c2) throws Exception {
295: if (childOf(c1, c2)) {
296: Command cr = (Command) ObjectCloner.deepCopy(c1);
297: cr.setPath(replacePath(c1.getPath(), c2.getNewPath()));
298:
299: return cr;
300: }
301:
302: return c1;
303: }
304:
305: public Command tf(Remove c1, UpdateBinaryFile c2) throws Exception {
306: return c1;
307: }
308:
309: /**
310: * Rename
311: */
312: public Command tf(Rename c1, AddFile c2) throws Exception {
313: return c1;
314: }
315:
316: public Command tf(Rename c1, AddDir c2) throws Exception {
317: return c1;
318: }
319:
320: public Command tf(Rename c1, Remove c2) throws Exception {
321: if (childOf(c1, c2)) {
322: return new NoOp(c1, ws);
323: }
324:
325: return c1;
326: }
327:
328: public Command tf(Rename c1, Rename c2) throws Exception {
329: if (c1.getPath().equals(c2.getPath())
330: && c1.getNewPath().equals(c2.getNewPath())) {
331: return new Id(c1, ws);
332: }
333:
334: if (childOf(c1, c2)) {
335: Rename cr = (Rename) ObjectCloner.deepCopy(c1);
336: cr.setPath(replacePath(c1.getPath(), c2.getNewPath()));
337: cr
338: .setNewPath(replacePath(c1.getNewPath(), c2
339: .getNewPath()));
340:
341: return cr;
342: }
343:
344: return c1;
345: }
346:
347: public Command tf(Rename c1, UpdateBinaryFile c2) throws Exception {
348: return c1;
349: }
350:
351: /**
352: * UpdateBinaryFile
353: */
354: public Command tf(UpdateBinaryFile c1, AddFile c2) throws Exception {
355: return c1;
356: }
357:
358: public Command tf(UpdateBinaryFile c1, AddDir c2) throws Exception {
359: return c1;
360: }
361:
362: public Command tf(UpdateBinaryFile c1, Remove c2) throws Exception {
363: if (childOf(c1, c2)) {
364: return new NoOp(c1, ws);
365: }
366:
367: return c1;
368: }
369:
370: public Command tf(UpdateBinaryFile c1, Rename c2) throws Exception {
371: if (childOf(c1, c2)) {
372: Command cr = (Command) ObjectCloner.deepCopy(c1);
373: cr.setPath(replacePath(c1.getPath(), c2.getNewPath()));
374:
375: return cr;
376: }
377:
378: return c1;
379: }
380:
381: public Command tf(UpdateBinaryFile c1, UpdateBinaryFile c2)
382: throws Exception {
383: if (c1.getPath().equals(c2.getPath())) {
384: if (FileUtils.compareBinFile(new File(c1.getAttachement()),
385: new File(c2.getAttachement()))) {
386: return new Id(c2, ws);
387: }
388:
389: // Conflict between the 2 ops
390: if (c1.getTicket() == -1) {
391: // c1 is the local op
392: Command cmd = new AddBinaryFile(uniquePath(c1, c2), ws,
393: c1.getAttachement());
394:
395: return cmd;
396: } else {
397: // c1 is the remote op
398: Macro m = new Macro(c1, ws);
399: Macro m1 = new Macro(m, ws);
400: m.setCommand(new Rename(c1.getPath(), ws, uniquePath(
401: c1, c2)), 1);
402: m.setCommand(m1, 2);
403: m1.setCommand(new AddBinaryFile(c1.getPath(), ws), 1);
404: m1.setCommand(c1, 2);
405: c1.setConflict(true);
406:
407: return m;
408: }
409: }
410:
411: return c1;
412: }
413:
414: /**
415: * Generic
416: */
417: public Command tf(UpdateFile c1, Remove c2) throws Exception {
418: if (childOf(c1, c2)) {
419: //System.out.println(" child");
420: return new NoOp(c1, ws);
421: }
422:
423: return c1;
424: }
425:
426: public Command tf(UpdateFile c1, Rename c2) throws Exception {
427: if (childOf(c1, c2)) {
428: Command cr = (Command) ObjectCloner.deepCopy(c1);
429: cr.setPath(replacePath(c1.getPath(), c2.getNewPath()));
430:
431: return cr;
432: }
433:
434: return c1;
435: }
436:
437: /**
438: * File System Util
439: */
440: public boolean childOf(Command c1, Command c2) {
441: return c1.getPath().startsWith(c2.getPath());
442: }
443:
444: // getParentPath('/1/2/3/4') will return '/1/2/3'
445: public static String getParentPath(String path) {
446: //System.out.println(path);
447: int lastIndex = path.lastIndexOf("/");
448:
449: if (lastIndex == -1) {
450: return "";
451: }
452:
453: return path.substring(0, lastIndex + 1);
454: }
455:
456: // getFSName('/1/2/3/4') will return '4'
457: public String getFSName(String path) {
458: //return path.substring(path.lastIndexOf(File.pathSeparatorChar)+1);
459: return path.substring(path.lastIndexOf("/") + 1);
460: }
461:
462: // replacePath('/1/2/3/4','/1/5') will return '/1/5/3/4'
463: // replacePath('/1/2/3/4','/1/2#')
464: // commonpath: /1/
465: // 2/3/4
466: // FSRenamed: 2#
467: // result /1/ 2# 2/3/4
468: public String replacePath(String pathToRename, String newPathToApply) {
469: String commonPath = getParentPath(newPathToApply);
470: assert pathToRename.startsWith(commonPath) : "bad replacement of path '"
471: + pathToRename + "' with '" + newPathToApply + "'";
472:
473: String FSRenamed = newPathToApply
474: .substring(commonPath.length());
475: String unchangedTail = pathToRename.substring(commonPath
476: .length());
477: int index = unchangedTail.indexOf("/");
478:
479: if (index == -1) {
480: unchangedTail = "";
481: } else {
482: unchangedTail = unchangedTail.substring(unchangedTail
483: .indexOf("/"));
484: }
485:
486: return commonPath + FSRenamed + unchangedTail;
487: }
488:
489: // generate a unique path which must be the same for uniquePath(c1,c2) and
490: // uniquePath(c2,c1)
491: public String uniquePath(Command c1, Command c2) {
492: long maxTicket = java.lang.Math.max(c1.getTicket(), c2
493: .getTicket());
494:
495: return new String(c1.getPath() + "#" + maxTicket);
496: }
497: }
|