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.client;
034:
035: import org.libresource.so6.core.compress.CompressUtil;
036: import org.libresource.so6.core.engine.OpVectorFsImpl;
037: import org.libresource.so6.core.engine.PatchFile;
038: import org.libresource.so6.core.engine.util.FileUtils;
039:
040: import java.io.File;
041: import java.io.FileInputStream;
042: import java.io.FileOutputStream;
043: import java.io.FileWriter;
044: import java.io.FilenameFilter;
045: import java.io.OutputStreamWriter;
046:
047: import java.util.ArrayList;
048: import java.util.Iterator;
049: import java.util.Properties;
050: import java.util.StringTokenizer;
051: import java.util.Vector;
052:
053: public class DummyClient implements ClientI {
054: private static String DEFAULT_BINEXT = "class pdf ps eps exe zip jar gif jpg png";
055:
056: /** Name of the queue property file */
057: public static String PROP_FILE = "so6.properties";
058:
059: /** Key name for the last ticket information in the property file */
060: public static String LAST_TICKET = "so6.last.ticket";
061:
062: /** Key name for the binary extention information in the property file */
063: public static String BINEXT = "so6.bin.ext";
064:
065: // liste des extensions binaires...
066:
067: /** Name of the local directory where the patch will be stored */
068: public static final String PATCHFILES = "PATCHFILES";
069:
070: /**
071: * Name of the local directory where the command during compression will be
072: * stored
073: */
074: public static final String CMDS = "CMDS";
075:
076: /**
077: * Name of the local directory where the attachement of the command will be
078: * stored
079: */
080: public static final String ATTACH = "ATTACH";
081: private String dir;
082: private Properties prop = new Properties();
083: private boolean loaded = false;
084: private Vector exts = new Vector();
085:
086: /**
087: * Create a So6 queue in a tmp directory
088: */
089: public DummyClient() throws Exception {
090: this (FileUtils.createTmpDir().getPath());
091: }
092:
093: /**
094: * Default constructor
095: *
096: * @param props
097: */
098: public DummyClient(Properties props) {
099: this (props.getProperty(SO6_QUEUE_ID));
100: }
101:
102: /**
103: * Create a So6 queue in the specified directory
104: *
105: * @param path
106: * the base path for the queue
107: */
108: public DummyClient(String path) {
109: this .dir = path;
110:
111: File d = new File(path);
112:
113: if (!d.exists() || (d.list().length == 0)) {
114: if (!d.exists() && !d.mkdirs()) {
115: throw new RuntimeException("Cannot create "
116: + d.getPath());
117: }
118:
119: prop.setProperty(DummyClient.LAST_TICKET, "0");
120: exts = DummyClient.readBinExt(DEFAULT_BINEXT);
121: save();
122: }
123:
124: d = new File(dir, PATCHFILES);
125:
126: if (!d.exists()) {
127: if (!d.mkdirs()) {
128: throw new RuntimeException("Cannot create "
129: + d.getPath());
130: }
131: }
132:
133: d = new File(dir, CMDS);
134:
135: if (!d.exists()) {
136: if (!d.mkdirs()) {
137: throw new RuntimeException("Cannot create "
138: + d.getPath());
139: }
140: }
141:
142: d = new File(dir, ATTACH);
143:
144: if (!d.exists()) {
145: if (!d.mkdirs()) {
146: throw new RuntimeException("Cannot create "
147: + d.getPath());
148: }
149: }
150:
151: load();
152: }
153:
154: /**
155: * Return the base path of the Dummy queue directory
156: *
157: * @return the base path of the queue.
158: */
159: public String getDummyPath() {
160: return dir;
161: }
162:
163: /**
164: * Load meta data from the queue property file
165: */
166: public void load() {
167: File propfile = new File(dir + File.separator
168: + DummyClient.PROP_FILE);
169:
170: if ((propfile.exists()) && (propfile.isFile())) {
171: try {
172: FileInputStream fis = new FileInputStream(propfile);
173: prop.load(fis);
174: exts = DummyClient.readBinExt(prop
175: .getProperty(DummyClient.BINEXT));
176: } catch (Exception e) {
177: e.printStackTrace();
178: throw new RuntimeException("Cannot read property file:"
179: + propfile.getPath());
180: }
181: } else {
182: throw new RuntimeException("Cannot find property file:"
183: + propfile.getPath());
184: }
185:
186: loaded = true;
187: }
188:
189: /**
190: * Save queue meta data
191: */
192: public void save() {
193: if (dir == null) { // true for testing...
194:
195: return;
196: }
197:
198: try {
199: FileOutputStream fos = new FileOutputStream(dir
200: + File.separator + DummyClient.PROP_FILE);
201: prop.setProperty(DummyClient.BINEXT, getBinExt());
202: prop.store(fos, "do not edit");
203: fos.close();
204: } catch (Exception e) {
205: throw new RuntimeException("Cannot save property file"
206: + dir + File.separator + DummyClient.PROP_FILE);
207: }
208: }
209:
210: public long getLastTicket() {
211: load();
212:
213: return Long
214: .parseLong(prop.getProperty(DummyClient.LAST_TICKET));
215: }
216:
217: private void setLastTicket(long i) {
218: prop.setProperty(DummyClient.LAST_TICKET, Long.toString(i));
219: this .save();
220: }
221:
222: public void addBinExt(String ext) {
223: if (!(exts.contains(ext))) {
224: exts.add(ext);
225: }
226: }
227:
228: public void removeBinExt(String ext) {
229: exts.remove(ext);
230: }
231:
232: public String getBinExt() {
233: StringBuffer sb = new StringBuffer();
234:
235: for (int i = 0; i < exts.size(); i++) {
236: sb.append(exts.get(i) + " ");
237: }
238:
239: return sb.toString();
240: }
241:
242: /**
243: * Split binary extention into a vector of extention
244: *
245: * @param s
246: * @return
247: */
248: public static Vector readBinExt(String s) {
249: Vector v = new Vector();
250: StringTokenizer st = new StringTokenizer(s);
251:
252: while (st.hasMoreTokens()) {
253: v.add(st.nextToken());
254: }
255:
256: return v;
257: }
258:
259: public void sendPatch(long ticket, long lasticket,
260: String patchfile, boolean validate) throws LocalException {
261: File f = new File(patchfile);
262:
263: if (ticket != (getLastTicket() + 1)) {
264: throw new LocalException("bad patch file, waiting for "
265: + (getLastTicket() + 1) + " got " + ticket);
266: }
267:
268: try {
269: FileUtils.copy(patchfile, dir + File.separator + PATCHFILES
270: + File.separator + ticket + "." + lasticket);
271: } catch (Exception e) {
272: throw new LocalException(e);
273: }
274:
275: setLastTicket(lasticket);
276: }
277:
278: public String getPatch(final long fromTicket) throws LocalException {
279: File d = new File(dir + File.separator + PATCHFILES);
280: String[] entries = d.list(new FilenameFilter() {
281: public boolean accept(File dir, String name) {
282: if (name.startsWith(Long.toString(fromTicket) + ".")) {
283: return true;
284: }
285:
286: return false;
287: }
288: });
289:
290: if (entries.length == 0) {
291: throw new LocalException("No patch available with ticket "
292: + fromTicket);
293: }
294:
295: long toTicket = fromTicket;
296:
297: for (int i = 0; i < entries.length; i++) {
298: long ticket = Long.parseLong(entries[i].split("\\.")[1]);
299:
300: if (ticket > toTicket) {
301: toTicket = ticket;
302: }
303: }
304:
305: return dir + File.separator + PATCHFILES + File.separator
306: + fromTicket + "." + toTicket;
307: }
308:
309: public String getPatch(final long fromTicket, final long toTicket)
310: throws LocalException {
311: File d = new File(dir + File.separator + PATCHFILES);
312: String patchName = fromTicket + "." + toTicket;
313: File f = new File(d, patchName);
314:
315: if (!f.exists()) {
316: throw new LocalException("Patch " + patchName
317: + " does not exist!!!");
318: }
319:
320: return f.getPath();
321: }
322:
323: // public ArrayList getPatchListFromTo(final long from, final long to)
324: // throws Exception {
325: // File d = new File(dir + File.separator + PATCHFILES);
326: // String[] allPatch = d.list();
327: // // Check that's possible
328: // boolean impossible = true;
329: // for (int i = 0; i < allPatch.length; i++) {
330: // if (allPatch[i].substring(allPatch[i].indexOf(".") +
331: // 1).equals(Long.toString(to))) {
332: // impossible = false;
333: // break;
334: // }
335: // }
336: // if (impossible)
337: // throw new Exception("Impossible to find a patch list to reach state of
338: // ticket " + to);
339: //
340: // // build the list
341: // long lastTicket = from;
342: // ArrayList result = new ArrayList();
343: // lastTicket++;
344: // while (lastTicket <= to) {
345: // String name = getPatch(lastTicket);
346: // lastTicket = Integer.parseInt(name.substring(name.lastIndexOf(".") + 1))
347: // + 1;
348: // result.add(name);
349: // }
350: // return result;
351: // }
352: public long[][] listPatch() {
353: File d = new File(dir + File.separator + PATCHFILES);
354: File patchFile = null;
355: String[] allPatch = d.list();
356: long[][] result = new long[allPatch.length][3];
357:
358: for (int i = 0; i < allPatch.length; i++) {
359: patchFile = new File(d, allPatch[i]);
360:
361: String[] tickets = allPatch[i].split("\\.");
362: result[i][0] = Long.parseLong(tickets[0]); // fromTicket
363: result[i][1] = Long.parseLong(tickets[1]); // toTicket
364: result[i][2] = patchFile.length(); // fileSize
365: }
366:
367: return result;
368: }
369:
370: /**
371: * Build an equivalent compressed patch.
372: *
373: * @return the path of that patch file
374: * @throws Exception
375: */
376: public String tagState() throws Exception {
377: File outputFile = new File(dir + File.separator + PATCHFILES,
378: "1." + getLastTicket());
379:
380: if (outputFile.exists()) {
381: return outputFile.getPath();
382: }
383:
384: long[][] patchList = listPatch();
385:
386: // find the shortest path
387: long ticket = 1;
388: long tmp = -1;
389: ArrayList path = new ArrayList();
390:
391: while (ticket < getLastTicket()) {
392: tmp = ticket;
393:
394: for (int i = 0; i < patchList.length; i++) {
395: long[] line = patchList[i];
396:
397: if (line[0] == ticket) {
398: if (tmp < line[1]) {
399: tmp = line[1];
400: }
401: }
402: }
403:
404: path.add(ticket + "." + tmp);
405: ticket = tmp + 1;
406: }
407:
408: OpVectorFsImpl opv = new OpVectorFsImpl(dir + File.separator
409: + CMDS);
410:
411: for (Iterator i = path.iterator(); i.hasNext();) {
412: String patchName = (String) i.next();
413: PatchFile pf = new PatchFile(dir + File.separator
414: + PATCHFILES + File.separator + patchName);
415: pf.buildOpVector(opv, dir + File.separator + ATTACH, null);
416: }
417:
418: CompressUtil.compressLog(opv);
419:
420: OutputStreamWriter osw = new FileWriter(outputFile);
421: PatchFile.makePatch(opv, osw, null, 1, getLastTicket(),
422: "compress", "patch");
423: osw.close();
424:
425: return outputFile.getPath();
426: }
427:
428: /**
429: * Construct a Dummy queue to the path specified in parameter.
430: *
431: * @param args
432: */
433: public static void main(String[] args) {
434: new DummyClient(new File(args[0]).getAbsolutePath());
435: }
436:
437: public static String[] getInternalPropertyList() {
438: return new String[] { SO6_QUEUE_ID };
439: }
440: }
|