KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > lenya > cms > rc > RCML


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17
18 /* $Id: RCML.java 43212 2004-08-15 04:23:03Z gregor $ */
19
20 package org.apache.lenya.cms.rc;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 import javax.xml.parsers.ParserConfigurationException JavaDoc;
30
31 import org.apache.lenya.xml.DocumentHelper;
32 import org.apache.lenya.xml.NamespaceHelper;
33 import org.apache.lenya.xml.XPointerFactory;
34 import org.apache.log4j.Category;
35 import org.w3c.dom.Document JavaDoc;
36 import org.w3c.dom.Element JavaDoc;
37 import org.w3c.dom.Node JavaDoc;
38 import org.w3c.dom.NodeList JavaDoc;
39
40 /**
41  * Handle with the RCML file
42  */

43 public class RCML {
44     private static Category log = Category.getInstance(RCML.class);
45
46     public static final short co = 0;
47     public static final short ci = 1;
48
49     private File JavaDoc rcmlFile;
50     private Document JavaDoc document = null;
51     private boolean dirty = false;
52     private int maximalNumberOfEntries = 5;
53
54     private static Map JavaDoc ELEMENTS = new HashMap JavaDoc();
55     protected static final String JavaDoc ELEMENT_CHECKIN = "CheckIn";
56     protected static final String JavaDoc ELEMENT_CHECKOUT = "CheckOut";
57     protected static final String JavaDoc ELEMENT_BACKUP = "Backup";
58
59     {
60         ELEMENTS.put(new Short JavaDoc(ci), ELEMENT_CHECKIN);
61         ELEMENTS.put(new Short JavaDoc(co), ELEMENT_CHECKOUT);
62     }
63
64     /**
65      * Creates a new RCML object.
66      */

67     public RCML() {
68         /*Deprecated
69         maximalNumberOfEntries = new org.apache.lenya.xml.Configuration().maxNumberOfRollbacks;
70         */

71         maximalNumberOfEntries = 10;
72         maximalNumberOfEntries = (2 * maximalNumberOfEntries) + 1;
73     }
74
75     /**
76      * create a RCML-File if no one exists already
77      *
78      * @param rcmlDirectory The rcml directory.
79      * @param filename The path of the file from the publication (e.g. for file with
80      * absolute path home/.../jakarta-tomcat-4.1.24/webapps/lenya/lenya/pubs/{publication id}/content/authoring/foo/bar.xml
81      * the filename is content/authoring/foo/bar.xml)
82      * @param rootDirectory The publication directory
83      *
84      * @throws Exception if an error occurs
85      */

86     public RCML(String JavaDoc rcmlDirectory, String JavaDoc filename, String JavaDoc rootDirectory) throws Exception JavaDoc {
87         this();
88         rcmlFile = new File JavaDoc(rcmlDirectory, filename + ".rcml");
89
90         if (!rcmlFile.isFile()) {
91             // The rcml file does not yet exist, so we create it now...
92
//
93
File JavaDoc dataFile = new File JavaDoc(rootDirectory, filename);
94             long lastModified = 0;
95
96             if (dataFile.isFile()) {
97                 lastModified = dataFile.lastModified();
98             }
99
100             initDocument();
101
102             // Create a "fake" checkin entry so it looks like the
103
// system checked the document in. We use the filesystem
104
// modification date as checkin time.
105
//
106
checkOutIn(RCML.ci, RevisionController.systemUsername, lastModified, false);
107
108             File JavaDoc parent = new File JavaDoc(rcmlFile.getParent());
109             parent.mkdirs();
110
111             write();
112         } else {
113             document = DocumentHelper.readDocument(rcmlFile);
114         }
115     }
116
117     /**
118      * initialise the RCML-document. Delete all entries
119      */

120     public void initDocument() throws ParserConfigurationException JavaDoc {
121         document = DocumentHelper.createDocument(null, "XPSRevisionControl", null);
122     }
123
124     /**
125      * Call the methode write, if the document is dirty
126      *
127      * @throws IOException if an error occurs
128      * @throws Exception if an error occurs
129      */

130     protected void finalize() throws IOException JavaDoc, Exception JavaDoc {
131         if (this.isDirty()) {
132             log.debug("RCML.finalize(): calling write()");
133             write();
134         }
135     }
136     /**
137      * Write the xml RCML-document in the RCML-file.
138      *
139      * @throws IOException if an error occurs
140      * @throws Exception if an error occurs
141      */

142     public void write() throws IOException JavaDoc, Exception JavaDoc {
143         DocumentHelper.writeDocument(document, rcmlFile);
144         clearDirty();
145     }
146
147     /**
148      * Write a new entry for a check out or a check in the RCML-File made by the user with identity
149      * at time
150      *
151      * @param type co for a check out, ci for a check in
152      * @param identity The identity of the user
153      * @param time Time at which the check in/out is made
154      *
155      * @throws IOException if an error occurs
156      * @throws Exception if an error occurs
157      */

158     public void checkOutIn(short type, String JavaDoc identity, long time, boolean backup)
159         throws IOException JavaDoc, Exception JavaDoc {
160
161         if (type != co && type != ci) {
162             throw new IllegalArgumentException JavaDoc(
163                 "ERROR: " + this.getClass().getName() + ".checkOutIn(): No such type");
164         }
165
166         NamespaceHelper helper = new NamespaceHelper(null, "", document);
167
168         Element JavaDoc identityElement = helper.createElement("Identity", identity);
169         Element JavaDoc timeElement = helper.createElement("Time", "" + time);
170
171         String JavaDoc elementName = (String JavaDoc) ELEMENTS.get(new Short JavaDoc(type));
172         Element JavaDoc checkOutElement = helper.createElement(elementName);
173
174         checkOutElement.appendChild(identityElement);
175         checkOutElement.appendChild(timeElement);
176
177         if (backup) {
178             Element JavaDoc backupElement = helper.createElement(ELEMENT_BACKUP);
179             checkOutElement.appendChild(backupElement);
180         }
181
182         Element JavaDoc root = document.getDocumentElement();
183         root.insertBefore(checkOutElement, root.getFirstChild());
184
185         setDirty();
186
187         // If this is a checkout, we write back the changed state
188
// to the file immediately because otherwise another
189
// process might read the file and think there is no open
190
// checkout (as it is only visible in our private DOM tree
191
// at this time).
192
//
193
// If, however, this is a checkin, we do not yet write it
194
// out because then another process might again check it
195
// out immediately and manipulate the file contents
196
// *before* our caller has finished writing back the
197
// changed data to the destination file. We therefore rely
198
// on either our caller invoking the write() method when
199
// finished or the garbage collector calling the finalize()
200
// method.
201
//
202
if (type == co) {
203             write();
204         }
205     }
206
207     /**
208      * get the latest check out
209      *
210      * @return CheckOutEntry The entry of the check out
211      *
212      * @throws Exception if an error occurs
213      */

214     public CheckOutEntry getLatestCheckOutEntry() throws Exception JavaDoc {
215         XPointerFactory xpf = new XPointerFactory();
216
217         Vector JavaDoc firstCheckOut =
218             xpf.select(
219                 document.getDocumentElement(),
220                 "xpointer(/XPSRevisionControl/CheckOut[1]/Identity)xpointer(/XPSRevisionControl/CheckOut[1]/Time)");
221
222         if (firstCheckOut.size() == 0) {
223             // No checkout at all
224
//
225
return null;
226         }
227
228         String JavaDoc[] fcoValues = xpf.getNodeValues(firstCheckOut);
229         long fcoTime = new Long JavaDoc(fcoValues[1]).longValue();
230
231         return new CheckOutEntry(fcoValues[0], fcoTime);
232     }
233
234     /**
235      * get the latest check in
236      *
237      * @return CheckInEntry The entry of the check in
238      *
239      * @throws Exception if an error occurs
240      */

241     public CheckInEntry getLatestCheckInEntry() throws Exception JavaDoc {
242         XPointerFactory xpf = new XPointerFactory();
243
244         Vector JavaDoc firstCheckIn =
245             xpf.select(
246                 document.getDocumentElement(),
247                 "xpointer(/XPSRevisionControl/CheckIn[1]/Identity)xpointer(/XPSRevisionControl/CheckIn[1]/Time)");
248
249         if (firstCheckIn.size() == 0) {
250             // No checkin at all
251
//
252
return null;
253         }
254
255         String JavaDoc[] fciValues = xpf.getNodeValues(firstCheckIn);
256         long fciTime = new Long JavaDoc(fciValues[1]).longValue();
257
258         return new CheckInEntry(fciValues[0], fciTime);
259     }
260
261     /**
262      * get the latest entry (a check out or check in)
263      *
264      * @return RCMLEntry The entry of the check out/in
265      *
266      * @throws Exception if an error occurs
267      */

268     public RCMLEntry getLatestEntry() throws Exception JavaDoc {
269         CheckInEntry cie = getLatestCheckInEntry();
270         CheckOutEntry coe = getLatestCheckOutEntry();
271
272         if ((cie != null) && (coe != null)) {
273             if (cie.getTime() > coe.getTime()) {
274                 return cie;
275             } else {
276                 return coe;
277             }
278         }
279
280         if (cie != null) {
281             return cie;
282         } else {
283             return coe;
284         }
285     }
286
287     /**
288      * get all check in and check out
289      *
290      * @return Vector of all check out and check in entries in this RCML-file
291      *
292      * @throws Exception if an error occurs
293      */

294     public Vector JavaDoc getEntries() throws Exception JavaDoc {
295         XPointerFactory xpf = new XPointerFactory();
296
297         Vector JavaDoc entries =
298             xpf.select(
299                 document.getDocumentElement(),
300                 "xpointer(/XPSRevisionControl/CheckOut|/XPSRevisionControl/CheckIn)");
301         Vector JavaDoc RCMLEntries = new Vector JavaDoc();
302
303         for (int i = 0; i < entries.size(); i++) {
304             Element JavaDoc elem = (Element JavaDoc) entries.get(i);
305             String JavaDoc time = elem.getElementsByTagName("Time").item(0).getFirstChild().getNodeValue();
306             String JavaDoc identity =
307                 elem.getElementsByTagName("Identity").item(0).getFirstChild().getNodeValue();
308
309             if (elem.getTagName().equals("CheckOut")) {
310                 RCMLEntries.add(new CheckOutEntry(identity, new Long JavaDoc(time).longValue()));
311             } else {
312                 RCMLEntries.add(new CheckInEntry(identity, new Long JavaDoc(time).longValue()));
313             }
314         }
315
316         return RCMLEntries;
317     }
318
319     /**
320      * Prune the list of entries and delete the corresponding backups. Limit the number of entries to the value
321      * maximalNumberOfEntries (2maxNumberOfRollbacks(configured)+1)
322      *
323      * @param backupDir The backup directory
324      *
325      * @throws Exception if an error occurs
326      */

327     public void pruneEntries(String JavaDoc backupDir) throws Exception JavaDoc {
328         XPointerFactory xpf = new XPointerFactory();
329
330         Vector JavaDoc entries =
331             xpf.select(
332                 document.getDocumentElement(),
333                 "xpointer(/XPSRevisionControl/CheckOut|/XPSRevisionControl/CheckIn)");
334
335         for (int i = maximalNumberOfEntries; i < entries.size(); i++) {
336             Element JavaDoc current = (Element JavaDoc) entries.get(i);
337
338             // remove the backup file associated with this entry
339
String JavaDoc time =
340                 current.getElementsByTagName("Time").item(0).getFirstChild().getNodeValue();
341             File JavaDoc backupFile = new File JavaDoc(backupDir + "/" + time + ".bak");
342             backupFile.delete();
343             // remove the entry from the list
344
current.getParentNode().removeChild(current);
345         }
346     }
347
348     /**
349      * Get a clone document
350      *
351      * @return org.w3c.dom.Document The clone document
352      *
353      * @throws Exception if an error occurs
354      */

355     public org.w3c.dom.Document JavaDoc getDOMDocumentClone() throws Exception JavaDoc {
356         Document JavaDoc documentClone = DocumentHelper.createDocument(null, "dummy", null);
357         documentClone.removeChild(documentClone.getDocumentElement());
358         documentClone.appendChild(documentClone.importNode(document.getDocumentElement(), true));
359
360         return documentClone;
361     }
362
363     /**
364      * Check if the document is dirty
365      *
366      * @return boolean dirty
367      */

368     public boolean isDirty() {
369         return dirty;
370     }
371
372     /**
373      * Set the value dirty to true
374      */

375     protected void setDirty() {
376         dirty = true;
377     }
378
379     /**
380      * Set the value dirty to false
381      */

382     protected void clearDirty() {
383         dirty = false;
384     }
385
386     /**
387      * Delete the latest check in
388      *
389      * @throws Exception if an error occurs
390      */

391     public void deleteFirstCheckIn() throws Exception JavaDoc {
392         XPointerFactory xpf = new XPointerFactory();
393         Node JavaDoc root = document.getDocumentElement();
394         Vector JavaDoc firstCheckIn = xpf.select(root, "xpointer(/XPSRevisionControl/CheckIn[1])");
395         root.removeChild((Node JavaDoc) firstCheckIn.elementAt(0));
396         root.removeChild(root.getFirstChild()); // remove EOL (end of line)
397
setDirty();
398     }
399
400     /**
401      * get the time's value of the backups
402      *
403      * @return String[] the times
404      *
405      * @throws Exception if an error occurs
406      */

407     public String JavaDoc[] getBackupsTime() throws Exception JavaDoc {
408         XPointerFactory xpf = new XPointerFactory();
409
410         Vector JavaDoc entries =
411             xpf.select(
412                 document.getDocumentElement(),
413                 "xpointer(/XPSRevisionControl/CheckIn)");
414         ArrayList JavaDoc times = new ArrayList JavaDoc();
415
416         for (int i = 0; i < entries.size(); i++) {
417             Element JavaDoc elem = (Element JavaDoc) entries.get(i);
418             String JavaDoc time = elem.getElementsByTagName("Time").item(0).getFirstChild().getNodeValue();
419             NodeList JavaDoc backupNodes = elem.getElementsByTagName(ELEMENT_BACKUP);
420             if (backupNodes != null && backupNodes.getLength()>0) {
421                 times.add(time);
422             }
423         }
424         return (String JavaDoc[]) times.toArray(new String JavaDoc[times.size()]);
425
426     }
427
428     /**
429      * delete the rcml file and the directory if this one is empty
430      *
431      * @return boolean true, if the file was deleted
432      */

433     public boolean delete() {
434         File JavaDoc rcmlFile = this.rcmlFile;
435         File JavaDoc directory = rcmlFile.getParentFile();
436         boolean deleted = rcmlFile.delete();
437         if (directory.exists()
438             && directory.isDirectory()
439             && directory.listFiles().length == 0) {
440             directory.delete();
441         }
442         return deleted;
443     }
444 }
445
Popular Tags