Source Code Cross Referenced for Archive.java in  » ERP-CRM-Financial » sakai » org » apache » commons » jrcs » rcs » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » sakai » org.apache.commons.jrcs.rcs 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * ====================================================================
0003:         *
0004:         * The Apache Software License, Version 1.1
0005:         *
0006:         * Copyright (c) 1999-2003 The Apache Software Foundation.
0007:         * All rights reserved.
0008:         *
0009:         * Redistribution and use in source and binary forms, with or without
0010:         * modification, are permitted provided that the following conditions
0011:         * are met:
0012:         *
0013:         * 1. Redistributions of source code must retain the above copyright
0014:         *    notice, this list of conditions and the following disclaimer.
0015:         *
0016:         * 2. Redistributions in binary form must reproduce the above copyright
0017:         *    notice, this list of conditions and the following disclaimer in
0018:         *    the documentation and/or other materials provided with the
0019:         *    distribution.
0020:         *
0021:         * 3. The end-user documentation included with the redistribution, if
0022:         *    any, must include the following acknowledgement:
0023:         *       "This product includes software developed by the
0024:         *        Apache Software Foundation (http://www.apache.org/)."
0025:         *    Alternately, this acknowledgement may appear in the software itself,
0026:         *    if and wherever such third-party acknowledgements normally appear.
0027:         *
0028:         * 4. The names "The Jakarta Project", "Commons", and "Apache Software
0029:         *    Foundation" must not be used to endorse or promote products derived
0030:         *    from this software without prior written permission. For written
0031:         *    permission, please contact apache@apache.org.
0032:         *
0033:         * 5. Products derived from this software may not be called "Apache"
0034:         *    nor may "Apache" appear in their names without prior written
0035:         *    permission of the Apache Software Foundation.
0036:         *
0037:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0038:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0039:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0040:         * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0041:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0042:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0043:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0044:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0045:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0046:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0047:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0048:         * SUCH DAMAGE.
0049:         * ====================================================================
0050:         *
0051:         * This software consists of voluntary contributions made by many
0052:         * individuals on behalf of the Apache Software Foundation.  For more
0053:         * information on the Apache Software Foundation, please see
0054:         * <http://www.apache.org/>.
0055:         *
0056:         */
0057:
0058:        package org.apache.commons.jrcs.rcs;
0059:
0060:        import java.io.*;
0061:        import java.util.*;
0062:
0063:        import org.apache.commons.jrcs.diff.Diff;
0064:        import org.apache.commons.jrcs.diff.DiffException;
0065:        import org.apache.commons.jrcs.diff.PatchFailedException;
0066:        import org.apache.commons.jrcs.util.ToString;
0067:
0068:        /**
0069:         * Handling of RCS/CVS style version control archives.
0070:         *
0071:         *
0072:         * <p>JRCS is a library that knows how to manipulate the archive files produced
0073:         * by the RCS and CVS version control systems. JRCS is not intended to replace
0074:         * neither tool. JRCS was written to be able create archive analysis tools
0075:         * that can do things like identify hot spots in the source code,
0076:         * measure the contributions by each developer,
0077:         * or assess how bugs make it in.</p>
0078:         *
0079:         * <p>The reasons why JRCS has the ability do do check-ins and save archives
0080:         * is API symmetry, and to simplify the writing of unit tests.</p>
0081:         *
0082:         * <p><b>CAVEAT UTILITOR:</b> Do not make modifications to your archives with JRCS.
0083:         * There needs to be an important amount of additional testing
0084:         * before it's safe to do that.</p>
0085:         *
0086:         * <p>The {@link org.apache.commons.jrcs.rcs rcs} package implements the
0087:         * archive handling functionality. The entry point to the library is class
0088:         * {@link org.apache.commons.jrcs.rcs.Archive Archive}.</p>
0089:         *
0090:         *
0091:         * <p>The {@link org.apache.commons.jrcs.diff diff} package implements
0092:         * the differencing engine that JRCS uses. The engine has the power of Unix diff,
0093:         * is simple to understand, and can be used independently of the archive handling
0094:         * functionality. The entry point to the differencing engine is class
0095:         * {@link org.apache.commons.jrcs.diff.Diff Diff}.</p>
0096:         *
0097:         * <p>Within this library, the word <i>text</i> means a unit of information
0098:         * subject to version control. The word <i>revision</i> means a particular
0099:         * version of a text. Each <i>revision</i> has a <i>version number</i>
0100:         * associated to it. <i>Version numbers</i> are dot-separated lists of numbers.
0101:         * Version numbers with an odd number of dots indicate revisions, while those
0102:         * with an even number of dots (including zero dots) designate branches.</p>
0103:         *
0104:         * <p>Revisions of a text are represented as <code>Object[]</code> because
0105:         * the diff engine is capable of handling more than plain text. In fact,
0106:         * arrays of any type that implements
0107:         * {@link java.lang.Object#hashCode hashCode()} and
0108:         * {@link java.lang.Object#equals equals()}
0109:         * correctly can be subject to differencing and version control using this
0110:         * library.</p>
0111:         *
0112:         * <p>To create an empty archive use:
0113:         * <code><pre>
0114:         *   Archive archive = new Archive();
0115:         * </pre></code>
0116:         * </p>
0117:         *
0118:         * <p>To read an archive from the file system, use:
0119:         * <code><pre>
0120:         *   Archive archive = new Archive("/path/to/archive,v");
0121:         * </pre></code>
0122:         * </p>
0123:         *
0124:         * <p>You can also initialize archives from streams.</p>
0125:         *
0126:         * <p>To retreive a revision from an archive use:
0127:         * <code><pre>
0128:         *   String versionNumber = "1.2";
0129:         *   Object[] text = archive.getRevision(versionNumber);
0130:         * </pre></code>
0131:         * </p>
0132:         *
0133:         * <p>You can also retreive revisions in such a way that each item
0134:         * is annotated with the version number of the revision in which it was
0135:         * last changed or added. To retrieve annotated text use:
0136:         * <code><pre>
0137:         *   String versionNumber = "1.2";
0138:         *   {@link Line Line[]} text = archive.getRevision(versionNumber);
0139:         *   for(int i = 0; i &lt; text.length(); i++)
0140:         *       System.out.println(text[i].revision.version);
0141:         * </pre></code>
0142:         * </p>
0143:         *
0144:         * <p>This class is NOT thread safe.</p>
0145:         * @see org.apache.commons.jrcs.diff
0146:         *
0147:         * @version $Id: Archive.java 2967 2005-10-26 10:52:33Z ian@caret.cam.ac.uk $
0148:         * @author <a href="mailto:juanco@suigeneris.org">Juanco Anez</a>
0149:         */
0150:        public class Archive extends ToString {
0151:            public static final String RCS_NEWLINE = "\n";
0152:
0153:            protected TrunkNode head;
0154:            protected Version branch;
0155:            protected Map nodes = new TreeMap(); //!!! check Node.compareTo for correct RCS order
0156:            protected Set users = new TreeSet();
0157:            protected Set locked = new TreeSet();
0158:            protected Map symbols = new TreeMap();
0159:            protected Phrases phrases = new Phrases();
0160:            protected String desc = new String();
0161:            protected boolean strictLocking = true;
0162:            protected String expand;
0163:            protected String comment = "# ";
0164:            protected String filename = "__unknown__,v";
0165:
0166:            // synchronize this if this has to be used in MT !
0167:            private static final KeywordsFormat FORMATTER = new KeywordsFormat();
0168:
0169:            /**
0170:             * Creates a new archive and sets the text of the initial revision.
0171:             * @param text The text of the initial revision.
0172:             * @param desc The archives description (not the log message).
0173:             */
0174:            public Archive(Object[] text, String desc) {
0175:                this (text, desc, new Version(1, 1));
0176:            }
0177:
0178:            /**
0179:             * Creates a new archive with the specified initial version number
0180:             * and sets the text of the initial revision.
0181:             * The initial revision must be of the form "n.m" (i.e. a trunk revision).
0182:             * @param text   The text of the initial revision.
0183:             * @param desc   The archives description (not the log message).
0184:             * @param vernum The initial revision number.
0185:             */
0186:            public Archive(Object[] text, String desc, String vernum) {
0187:                this (text, desc, new Version(vernum));
0188:            }
0189:
0190:            /**
0191:             * Creates a new archive with the specified initial version number
0192:             * and sets the text of the initial revision.
0193:             * The initial revision must be of the form "n.m" (i.e. a trunk revision).
0194:             * @param text   The text of the initial revision.
0195:             * @param desc   The archives description (not the log message).
0196:             * @param vernum The initial revision number.
0197:             */
0198:            public Archive(Object[] text, String desc, Version vernum) {
0199:                // can only add a trunk version
0200:                if (vernum.size() > 2) {
0201:                    throw new InvalidVersionNumberException(vernum
0202:                            + " must be a trunk version");
0203:                }
0204:                while (vernum.size() < 2) {
0205:                    vernum = vernum.newBranch(1);
0206:                }
0207:                // now add the _head node
0208:                this .head = (TrunkNode) newNode(vernum, null);
0209:                this .head.setText(text);
0210:                this .head.setLog(desc);
0211:            }
0212:
0213:            /**
0214:             * Load an archive from an input stream.
0215:             * Parses the archive given by the input stream, and gives it the provided name.
0216:             * @param fname The name to give to the archive.
0217:             * @param input Where to read the archive from
0218:             */
0219:            public Archive(String fname, InputStream input)
0220:                    throws ParseException {
0221:                this .filename = fname;
0222:                ArchiveParser.load(this , input);
0223:            }
0224:
0225:            /**
0226:             * Load an archive from an a file given by name.
0227:             * @param path The path to the file wher the archive resides.
0228:             */
0229:            public Archive(String path) throws ParseException,
0230:                    FileNotFoundException {
0231:                this .filename = new File(path).getPath();
0232:                ArchiveParser.load(this , this .filename);
0233:            }
0234:
0235:            /**
0236:             * Create an unitialized Archive.
0237:             * Used internally by the ArchiveParser.
0238:             * @see ArchiveParser
0239:             */
0240:            Archive() {
0241:            }
0242:
0243:            /**
0244:             * Set the name of the file for this archive
0245:             * @param path The full path name.
0246:             */
0247:            public void setFileName(String path) {
0248:                this .filename = path;
0249:            }
0250:
0251:            /**
0252:             * Save the archive to the provided stream.
0253:             * @param output The stream to save the archive to.
0254:             */
0255:            public void save(OutputStream output) throws IOException {
0256:                output.write(toByteArray());
0257:            }
0258:
0259:            /**
0260:             * Save the archive to a file and the the Archives filename
0261:             * accordingly.
0262:             * @param path The file's path.
0263:             */
0264:            public void save(String path) throws IOException {
0265:                OutputStream output = new FileOutputStream(path);
0266:                try {
0267:                    save(output);
0268:                    this .filename = new File(path).getPath();
0269:                } finally {
0270:                    output.close();
0271:                }
0272:            }
0273:
0274:            /**
0275:             * Add a head node with the given version number.
0276:             * @param vernum The version number to use.
0277:             */
0278:            protected void setHead(Version vernum)
0279:                    throws InvalidVersionNumberException {
0280:                if (head != null) {
0281:                    throw new HeadAlreadySetException(head.getVersion());
0282:                }
0283:                head = new TrunkNode(vernum, null);
0284:                nodes.put(vernum, head);
0285:            }
0286:
0287:            /**
0288:             * Set the active branch to the one identified by the given version number.
0289:             * Incomplete version numbers of the form "1" or "2.1.3" are accepted.
0290:             * @param v The version number.
0291:             */
0292:            public void setBranch(String v)
0293:                    throws InvalidBranchVersionNumberException {
0294:                setBranch(new Version(v));
0295:            }
0296:
0297:            /**
0298:             * Set the active branch to the one identified by the given version number.
0299:             * @param vernum The version number.
0300:             */
0301:            public void setBranch(Version vernum)
0302:                    throws InvalidBranchVersionNumberException {
0303:                if (!vernum.isBranch()) {
0304:                    throw new InvalidBranchVersionNumberException(vernum);
0305:                }
0306:                if (head == null
0307:                        || vernum.getBase(2).isGreaterThan(head.getVersion())) {
0308:                    throw new InvalidBranchVersionNumberException(vernum
0309:                            + "is greater than _head version "
0310:                            + head.getVersion());
0311:                }
0312:                branch = vernum;
0313:            }
0314:
0315:            /** Add a user name to the list of archive users.
0316:             * @param name The user name.
0317:             */
0318:            public void addUser(String name) {
0319:                users.add(name);
0320:            }
0321:
0322:            /**
0323:             * Tag a given version with a symbol.
0324:             * @param sym The tag.
0325:             * @param vernum The version to tag.
0326:             */
0327:            public void addSymbol(String sym, Version vernum)
0328:                    throws InvalidVersionNumberException {
0329:                //@TODO: Verify if the symbol is valid  
0330:                symbols.put(sym, vernum);
0331:            }
0332:
0333:            /**
0334:             * Returns a Map of the symbols (tags) associated with each revision.
0335:             * The symbols are the keys and the revision numbers are the values.
0336:             * @return A map of symbol/revision number pairs.
0337:             */
0338:            public Map getSymbols() {
0339:                return symbols;
0340:            }
0341:
0342:            /**
0343:             * Add a lock over a revison.
0344:             * @param user The user that locks the revision.
0345:             * @param vernum The version number of the revision to lock.
0346:             */
0347:            public void addLock(String user, Version vernum)
0348:                    throws InvalidVersionNumberException, NodeNotFoundException {
0349:                addUser(user);
0350:                Node node = newNode(vernum);
0351:                node.setLocker(user);
0352:                if (user == null) {
0353:                    locked.remove(node);
0354:                } else {
0355:                    locked.add(node);
0356:                }
0357:            }
0358:
0359:            /**
0360:             * Set the strict locking flag for the archive.
0361:             * @param value Indicates if strict locking should be on or off.
0362:             */
0363:            public void setStrictLocking(boolean value) {
0364:                strictLocking = value;
0365:            }
0366:
0367:            /**
0368:             * Set the keyword expansion flag for the archive.
0369:             * @param value The keyword expansion value. It should be one of:
0370:             * <ul>
0371:             * <li>     kv   (Default) Substitue keyword and value.
0372:             * <li>     kvl  Substitute keyword, value, and locker (if any).
0373:             * <li>     k    Substitute keyword only.
0374:             * <li>     o    Preserve original string.
0375:             * <li>     b    Like o, but mark file as binary.
0376:             * <li>     v    Substitue value only.
0377:             * </ul>
0378:             */
0379:            public void setExpand(String value) {
0380:                expand = value;
0381:            }
0382:
0383:            /**
0384:             * Set the archive's comment.
0385:             * @param value The comment.
0386:             */
0387:            public void setComment(String value) {
0388:                comment = value;
0389:            }
0390:
0391:            /**
0392:             * Set the archives description.
0393:             * @param value The descriptions text.
0394:             */
0395:            public void setDesc(String value) {
0396:                desc = value;
0397:            }
0398:
0399:            /**
0400:             * Add a new phrase to the archive.
0401:             * Phrases are used to provide for extensions of the archive format.
0402:             * Each phrase has a key and a list of values associated with it.
0403:             * @param key The phrases key.
0404:             * @param values The values under the key.
0405:             */
0406:            public void addPhrase(String key, Collection values) {
0407:                phrases.put(key, values);
0408:            }
0409:
0410:            protected Node newNode(Version vernum) {
0411:                return newNode(vernum, null);
0412:            }
0413:
0414:            protected Node newNode(Version vernum, Node prev)
0415:                    throws InvalidVersionNumberException, NodeNotFoundException {
0416:                if (!vernum.isRevision()) {
0417:                    throw new InvalidVersionNumberException(vernum);
0418:                }
0419:                Node node = (Node) nodes.get(vernum);
0420:                if (node == null) {
0421:                    node = Node.newNode(vernum, prev);
0422:                    nodes.put(vernum, node);
0423:                }
0424:                return node;
0425:            }
0426:
0427:            protected TrunkNode newTrunkNode(Version vernum)
0428:                    throws InvalidVersionNumberException, NodeNotFoundException {
0429:                if (!vernum.isTrunk()) {
0430:                    throw new InvalidTrunkVersionNumberException(vernum);
0431:                }
0432:                return (TrunkNode) newNode(vernum);
0433:            }
0434:
0435:            protected BranchNode newBranchNode(Version vernum)
0436:                    throws InvalidVersionNumberException, NodeNotFoundException {
0437:                if (!vernum.isBranch()) {
0438:                    throw new InvalidBranchVersionNumberException(vernum);
0439:                }
0440:                return (BranchNode) newNode(vernum);
0441:            }
0442:
0443:            protected Node getNode(Version vernum)
0444:                    throws InvalidVersionNumberException, NodeNotFoundException {
0445:                if (!vernum.isRevision()) {
0446:                    throw new InvalidVersionNumberException(vernum);
0447:                }
0448:                Node node = (Node) nodes.get(vernum);
0449:                if (node == null) {
0450:                    throw new NodeNotFoundException(vernum);
0451:                }
0452:                return node;
0453:            }
0454:
0455:            /**
0456:             * Return the node with the version number that matches the one provided.
0457:             * The given version number may be partial.
0458:             * @param vernum the version number to match.
0459:             * @return the node, or null if no match found.
0460:             */
0461:            public Node findNode(Version vernum) {
0462:                Path path = getRevisionPath(vernum);
0463:                return (path == null ? null : path.last());
0464:            }
0465:
0466:            /**
0467:             * Place a string image of the archive in the given StringBuffer.
0468:             * @param s Where the image shoul go.
0469:             */
0470:            public void toString(StringBuffer s) {
0471:                toString(s, RCS_NEWLINE);
0472:            }
0473:
0474:            /**
0475:             * Return a text image of the archive.
0476:             * @param EOL The token to use as line separator.
0477:             * @return The text image of the archive.
0478:             */
0479:            public String toString(String EOL) {
0480:                StringBuffer s = new StringBuffer();
0481:                toString(s, EOL);
0482:                return s.toString();
0483:            }
0484:
0485:            /**
0486:             * Return a text image of the archive as a char array.
0487:             * This is useful for writing the archive to a file without
0488:             * having the characters be interpreted by the writer.
0489:             * @return The archive image.
0490:             */
0491:            public char[] toCharArray() {
0492:                return toString(Archive.RCS_NEWLINE).toCharArray();
0493:            }
0494:
0495:            /**
0496:             * Return a text image of the archive as a char array.
0497:             * This is useful for writing the archive to a file without
0498:             * having the characters be interpreted by the writer.
0499:             * @return The archive image.
0500:             */
0501:            public byte[] toByteArray() {
0502:                return toString(Archive.RCS_NEWLINE).getBytes();
0503:            }
0504:
0505:            /**
0506:             * Returns the path from the head node to the node identified
0507:             * by the given version number.
0508:             * @param vernum The version number that identifies the final node.
0509:             * Partial version numbers are OK.
0510:             * @return The path to the node, or null if not found.
0511:             */
0512:            protected Path getRevisionPath(Version vernum) {
0513:                if (head == null) {
0514:                    return null;
0515:                }
0516:                try {
0517:                    Path path = head.pathTo(vernum, true);
0518:                    Node revisionFound = path.last();
0519:                    if (revisionFound == null) {
0520:                        return null;
0521:                    }
0522:                    if (revisionFound.getVersion().isLessThan(vernum)) {
0523:                        return null;
0524:                    }
0525:                    return path;
0526:                } catch (NodeNotFoundException e) {
0527:                    return null;
0528:                }
0529:            }
0530:
0531:            /**
0532:             * Return the actual revision number of the node identified
0533:             * by the given version number.
0534:             * @param vernum The version number that identifies the node.
0535:             * Partial version numbers are OK.
0536:             * @return The actual version, or null if a node is not found.
0537:             */
0538:            public Version getRevisionVersion(Version vernum) {
0539:                Path path = getRevisionPath(vernum);
0540:                return (path == null ? null : path.last().getVersion());
0541:            }
0542:
0543:            /**
0544:             * Return the actual revision number of the node identified
0545:             * by the given version number.
0546:             * @param vernum The version number that identifies the node.
0547:             * Partial version numbers are OK.
0548:             * @return The actual version, or null if a node is not found.
0549:             */
0550:            public Version getRevisionVersion(String vernum) {
0551:                return getRevisionVersion(new Version(vernum));
0552:            }
0553:
0554:            /**
0555:             * Return the actual revision number of the active revision.
0556:             * The revision will be the tip of the branch identified as
0557:             * active, or the head revision of the trunk if no branch is set
0558:             * as active.
0559:             * @return The version number of the active revision, or null if
0560:             * there is none.
0561:             */
0562:            public Version getRevisionVersion() {
0563:                if (branch != null) {
0564:                    return getRevisionVersion(branch);
0565:                } else if (head != null) {
0566:                    return head.getVersion();
0567:                } else {
0568:                    return null;
0569:                }
0570:            }
0571:
0572:            /**
0573:             * Append a text image of the archive to the given buffer using
0574:             * the given token as line separator.
0575:             * @param s  where to append the image.
0576:             * @param EOL the line separator.
0577:             */
0578:            public void toString(StringBuffer s, String EOL) {
0579:                String EOI = ";" + EOL;
0580:                String NLT = EOL + "\t";
0581:
0582:                s.append("head");
0583:                if (head != null) {
0584:                    s.append("\t");
0585:                    head.getVersion().toString(s);
0586:                }
0587:                s.append(EOI);
0588:
0589:                if (branch != null) {
0590:                    s.append("branch\t");
0591:                    s.append(branch.toString());
0592:                    s.append(EOI);
0593:                }
0594:
0595:                s.append("access");
0596:                for (Iterator i = users.iterator(); i.hasNext();) {
0597:                    s.append(EOL);
0598:                    s.append("\t");
0599:                    s.append(i.next());
0600:                }
0601:                s.append(EOI);
0602:
0603:                s.append("symbols");
0604:                for (Iterator i = symbols.entrySet().iterator(); i.hasNext();) {
0605:                    Map.Entry e = (Map.Entry) i.next();
0606:                    s.append(NLT);
0607:                    s.append(e.getKey().toString());
0608:                    s.append(":");
0609:                    s.append(e.getValue().toString());
0610:                }
0611:                s.append(EOI);
0612:
0613:                s.append("locks");
0614:                for (Iterator i = locked.iterator(); i.hasNext();) {
0615:                    String locker = ((Node) i.next()).getLocker();
0616:                    s.append(NLT);
0617:                    s.append(locker);
0618:                }
0619:                if (strictLocking) {
0620:                    s.append("; strict");
0621:                }
0622:                s.append(EOI);
0623:
0624:                if (comment != null) {
0625:                    s.append("comment\t");
0626:                    s.append(Archive.quoteString(comment));
0627:                    s.append(EOI);
0628:                }
0629:
0630:                if (expand != null) {
0631:                    s.append("expand\t");
0632:                    s.append(Archive.quoteString(expand));
0633:                    s.append(EOI);
0634:                }
0635:
0636:                if (phrases != null) {
0637:                    phrases.toString(s, EOL);
0638:                }
0639:                s.append(EOL);
0640:
0641:                for (Iterator i = nodes.values().iterator(); i.hasNext();) {
0642:                    Node n = (Node) i.next();
0643:                    if (!n.getVersion().isGhost() && n.getText() != null) {
0644:                        n.toString(s, EOL);
0645:                    }
0646:                }
0647:
0648:                s.append(EOL + EOL);
0649:                s.append("desc");
0650:                s.append(EOL);
0651:                s.append(quoteString(desc));
0652:                s.append(EOL);
0653:
0654:                Node n = head;
0655:                while (n != null) {
0656:                    n.toText(s, EOL);
0657:                    n = n.getRCSNext();
0658:                }
0659:            }
0660:
0661:            /**
0662:             * Quote a string.
0663:             * RCS strings are quoted using @. Any @ in the original
0664:             * string is doubled to @@.
0665:             * @param s the string to quote.
0666:             * @return The string quoted in RCS style.
0667:             */
0668:            static public String quoteString(String s) {
0669:                //!!! use org.apache.commons.jrcs.RegExp here !!!
0670:                StringBuffer result = new StringBuffer(s);
0671:                for (int i = 0; i < s.length(); i++) {
0672:                    if (result.charAt(i) == '@') {
0673:                        result.insert(i++, '@');
0674:                    }
0675:                }
0676:                result.insert(0, '@');
0677:                result.append('@');
0678:                return new String(result);
0679:            }
0680:
0681:            /**
0682:             * Unquote a string quoted in RCS style.
0683:             * @param s the quoted string.
0684:             * @return s the string unquoted.
0685:             */
0686:            static public String unquoteString(String s) {
0687:                return unquoteString(s, true);
0688:            }
0689:
0690:            /**
0691:             * Unquote a string quoted in RCS style.
0692:             * @param s the quoted string.
0693:             * @param removeExtremes Determines if the enclosing @ quotes
0694:             * should be removed.
0695:             * @return s the string unquoted.
0696:             */
0697:            static public String unquoteString(String s, boolean removeExtremes) {
0698:                //!!! use org.apache.commons.jrcs.RegExp here !!!
0699:                //!!! always ignore extremes. Check they are @'s, though.
0700:                StringBuffer result = new StringBuffer();
0701:                int start = 0;
0702:                int end = s.length();
0703:                if (removeExtremes) {
0704:                    start += 1;
0705:                    end -= 1;
0706:                }
0707:                for (int i = start; i < end; i++) {
0708:                    char c = s.charAt(i);
0709:                    result.append(c);
0710:                    if (c == '@') {
0711:                        i++;
0712:                    }
0713:                }
0714:                return new String(result);
0715:            }
0716:
0717:            /**
0718:             * Get the text belonging to the head revision.
0719:             * @return The text of the head revision
0720:             * @throws NodeNotFoundException if the revision could not be found.
0721:             * @throws InvalidFileFormatException if any of the deltas cannot be parsed.
0722:             * @throws PatchFailedException if any of the deltas could not be applied
0723:             */
0724:            public Object[] getRevision() throws InvalidFileFormatException,
0725:                    PatchFailedException, NodeNotFoundException {
0726:                return getRevision(false);
0727:            }
0728:
0729:            /**
0730:             * Get the text belonging to the head revision.
0731:             * Set annotate to true to have the lines be annotated with the
0732:             * number of the revision in which they were added or changed.
0733:             * @param annotate set to true to have the text be annotated
0734:             * @return The text of the head revision
0735:             * @throws NodeNotFoundException if the revision could not be found.
0736:             * @throws InvalidFileFormatException if any of the deltas cannot be parsed.
0737:             * @throws PatchFailedException if any of the deltas could not be applied
0738:             * to produce a new revision.
0739:             */
0740:            public Object[] getRevision(boolean annotate)
0741:                    throws InvalidFileFormatException, PatchFailedException,
0742:                    NodeNotFoundException {
0743:                if (branch != null) {
0744:                    return getRevision(branch);
0745:                } else if (head != null) {
0746:                    return getRevision(head.getVersion());
0747:                } else {
0748:                    throw new IllegalStateException("no head node");
0749:                }
0750:            }
0751:
0752:            /**
0753:             * Get the text belonging to the revision identified by the
0754:             * given version number.
0755:             * Partial version numbers are OK.
0756:             * @param vernum the version number.
0757:             * @return The text of the revision if found.
0758:             * @throws InvalidVersionNumberException if the version number cannot be parsed.
0759:             * @throws NodeNotFoundException if the revision could not be found.
0760:             * @throws InvalidFileFormatException if any of the deltas cannot be parsed.
0761:             * @throws PatchFailedException if any of the deltas could not be applied
0762:             */
0763:            public Object[] getRevision(String vernum)
0764:                    throws InvalidFileFormatException, PatchFailedException,
0765:                    InvalidVersionNumberException, NodeNotFoundException {
0766:                return getRevision(vernum, false);
0767:            }
0768:
0769:            /**
0770:             * Get the text belonging to the revision identified by the
0771:             * given version number.
0772:             * Partial version numbers are OK.
0773:             * Set annotate to true to have the lines be annotated with the
0774:             * number of the revision in which they were added or changed.
0775:             * @param vernum the version number.
0776:             * @param annotate set to true to have the text be annotated
0777:             * @return The text of the revision if found.
0778:             * @throws InvalidVersionNumberException if the version number cannot be parsed.
0779:             * @throws NodeNotFoundException if the revision could not be found.
0780:             * @throws InvalidFileFormatException if any of the deltas cannot be parsed.
0781:             * @throws PatchFailedException if any of the deltas could not be applied
0782:             */
0783:            public Object[] getRevision(String vernum, boolean annotate)
0784:                    throws InvalidVersionNumberException,
0785:                    NodeNotFoundException, InvalidFileFormatException,
0786:                    PatchFailedException {
0787:                return getRevision(new Version(vernum), annotate);
0788:            }
0789:
0790:            /**
0791:             * Get the text belonging to the revision identified by the
0792:             * given version number.
0793:             * Partial version numbers are OK.
0794:             * @param vernum the version number.
0795:             * @return The text of the revision if found.
0796:             * @throws NodeNotFoundException if the revision could not be found.
0797:             * @throws InvalidFileFormatException if any of the deltas cannot be parsed.
0798:             * @throws PatchFailedException if any of the deltas could not be applied
0799:             */
0800:            public Object[] getRevision(Version vernum)
0801:                    throws InvalidFileFormatException, PatchFailedException,
0802:                    NodeNotFoundException {
0803:                return getRevision(vernum, false);
0804:            }
0805:
0806:            /**
0807:             * Get the text belonging to the revision identified by the
0808:             * given version number.
0809:             * Partial version numbers are OK.
0810:             * Set annotate to true to have the lines be annotated with the
0811:             * number of the revision in which they were added or changed.
0812:             * @param vernum the version number.
0813:             * @param annotate set to true to have the text be annotated
0814:             * @return The text of the revision if found.
0815:             * @throws NodeNotFoundException if the revision could not be found.
0816:             * @throws InvalidFileFormatException if any of the deltas cannot be parsed.
0817:             * @throws PatchFailedException if any of the deltas could not be applied
0818:             */
0819:            public Object[] getRevision(Version vernum, boolean annotate)
0820:                    throws InvalidFileFormatException, PatchFailedException,
0821:                    NodeNotFoundException {
0822:                Path path = getRevisionPath(vernum);
0823:                if (path == null) {
0824:                    throw new NodeNotFoundException(vernum);
0825:                }
0826:                Lines lines = new Lines();
0827:                Node revisionFound = path.last();
0828:                path.patch(lines, annotate);
0829:
0830:                return doKeywords(lines.toArray(), revisionFound);
0831:            }
0832:
0833:            /**
0834:             * Add the given revision to the active branch on the archive.
0835:             * @param text the text of the revision.
0836:             * @param log the log: a short note explaining what the revision is.
0837:             * @return The version number assigned to the revision.
0838:             */
0839:            public Version addRevision(Object[] text, String log)
0840:                    throws InvalidFileFormatException, DiffException,
0841:                    InvalidVersionNumberException, NodeNotFoundException {
0842:                if (branch != null) {
0843:                    return addRevision(text, branch, log);
0844:                } else {
0845:                    return addRevision(text, head.getVersion().next(), log);
0846:                }
0847:            }
0848:
0849:            /**
0850:             * Add the given revision to the the archive using the given version
0851:             * number.
0852:             * The version number may be partial. If so, the rules used by RCS/CVS
0853:             * are used to decide which branch the revision should be added to. A
0854:             * new branch may be created if required.
0855:             * @param text the text of the revision.
0856:             * @param vernum is the version number wanted, or, if partial, identifies
0857:             * the target branch.
0858:             * @param log the log: a short note explaining what the revision is.
0859:             * @return The version number assigned to the revision.
0860:             */
0861:            public Version addRevision(Object[] text, String vernum, String log)
0862:                    throws InvalidFileFormatException, DiffException,
0863:                    InvalidVersionNumberException, NodeNotFoundException {
0864:                return addRevision(text, new Version(vernum), log);
0865:            }
0866:
0867:            /**
0868:             * Add the given revision to the the archive using the given version
0869:             * number.
0870:             * The version number may be partial. If so, the rules used by RCS/CVS
0871:             * are used to decide which branch the revision should be added to. A
0872:             * new branch may be created if required.
0873:             * @param text the text of the revision.
0874:             * @param vernum is the version number wanted, or, if partial, identifies
0875:             * the target branch.
0876:             * @param log the log: a short note explaining what the revision is.
0877:             * @return The version number assigned to the revision.
0878:             */
0879:            public Version addRevision(Object[] text, Version vernum, String log)
0880:                    throws InvalidFileFormatException, DiffException,
0881:                    NodeNotFoundException, InvalidVersionNumberException {
0882:                if (head == null) {
0883:                    throw new IllegalStateException("no head node");
0884:                }
0885:
0886:                Path path = head.pathTo(vernum, true);
0887:                Node target = path.last();
0888:
0889:                if (vernum.size() < target.getVersion().size()) {
0890:                    vernum = target.nextVersion();
0891:                } else if (!vernum.isGreaterThan(target.getVersion())) {
0892:                    throw new InvalidVersionNumberException(vernum
0893:                            + " revision must be higher than "
0894:                            + target.getVersion());
0895:                } else if (vernum.odd()) {
0896:                    if (vernum.last() == 0) {
0897:                        vernum = target.newBranchVersion();
0898:                    } else {
0899:                        vernum = vernum.newBranch(1);
0900:                    }
0901:                } else if (vernum.last() == 0) {
0902:                    vernum = vernum.next();
0903:                }
0904:
0905:                boolean headAdd = (target == head && !vernum.isBranch());
0906:
0907:                text = removeKeywords(text);
0908:                String deltaText;
0909:                if (headAdd) {
0910:                    deltaText = Diff.diff(text, head.getText()).toRCSString(
0911:                            RCS_NEWLINE);
0912:                } else {
0913:                    Object[] oldText = path.patch().toArray();
0914:                    deltaText = Diff.diff(oldText, text).toRCSString(
0915:                            RCS_NEWLINE);
0916:                }
0917:                if (deltaText.length() == 0) {
0918:                    return null;
0919:                } // no changes, no new version
0920:
0921:                Node newNode = null;
0922:                if (headAdd) {
0923:                    newNode = newNode(vernum, head);
0924:                    newNode.setText(text);
0925:                    head.setText(deltaText);
0926:                    head = (TrunkNode) newNode;
0927:                } else { // adding a branch node
0928:                    newNode = newNode(vernum);
0929:                    newNode.setText(deltaText);
0930:                    if (vernum.size() > target.getVersion().size()) {
0931:                        target.addBranch((BranchNode) newNode);
0932:                    } else {
0933:                        target.setRCSNext(newNode);
0934:                    }
0935:                }
0936:                newNode.setLog(log);
0937:                return newNode.getVersion();
0938:            }
0939:
0940:            /**
0941:             * Returns the given text with values added to CVS-style keywords.
0942:             * @param text the text on which substitutions will be applied.
0943:             * @param  rev a node that identifies the revision to which the
0944:             * given text belongs.
0945:             * @return the text with substitutions performed.
0946:             */
0947:            public Object[] doKeywords(Object[] text, Node rev)
0948:                    throws PatchFailedException {
0949:
0950:                //!!! this is used specifically for the way
0951:                //!!! in which the keyword replacer works. Should be moved there.
0952:                //!!! Write a Format.format(Object[], Node rev) instead.
0953:                Object[] revisionInfo = new Object[] { filename,
0954:                        new File(filename).getName(),
0955:                        rev.getVersion().toString(), rev.getDate(),
0956:                        rev.getAuthor(), rev.getState(), rev.getLocker() };
0957:
0958:                Object[] result = new Object[text.length];
0959:                for (int i = 0; i < text.length; i++) {
0960:                    result[i] = FORMATTER.update(text[i].toString(),
0961:                            revisionInfo);
0962:                }
0963:                return result;
0964:            }
0965:
0966:            /**
0967:             * Returns the given text removing the values of any CVS-style
0968:             * keywords.
0969:             * @param text the text on which substitutions will be applied.
0970:             * @return the text with substitutions performed.
0971:             */
0972:            protected static Object[] removeKeywords(Object[] text)
0973:                    throws PatchFailedException {
0974:                Object[] result = new Object[text.length];
0975:                for (int i = 0; i < text.length; i++) {
0976:                    result[i] = FORMATTER.reset(text[i].toString());
0977:                }
0978:                return result;
0979:            }
0980:
0981:            /**
0982:             * Return the list of nodes between the head revision and
0983:             * the root revision.
0984:             */
0985:            public Node[] changeLog() {
0986:                return changeLog(head.version);
0987:            }
0988:
0989:            /**
0990:             * Return the list of nodes between the the given revision
0991:             * and the root revision.
0992:             * @param latest the version of the last revision in the log.
0993:             */
0994:            public Node[] changeLog(Version latest) {
0995:                return changeLog(latest, head.root().version);
0996:            }
0997:
0998:            /**
0999:             * Return the list of nodes between the the given two revisions.
1000:             * @param latest the version of the last revision in the log.
1001:             * @param earliest the version of the first revision in the log.
1002:             */
1003:            public Node[] changeLog(Version latest, Version earliest) {
1004:                Node last = findNode(latest);
1005:                if (last == null) {
1006:                    throw new NodeNotFoundException(latest.toString());
1007:                }
1008:
1009:                Node first = findNode(earliest);
1010:                if (first == null) {
1011:                    throw new NodeNotFoundException(earliest.toString());
1012:                }
1013:
1014:                List result = new LinkedList();
1015:
1016:                Node node = last;
1017:                while (node != null) {
1018:                    result.add(0, node);
1019:                    if (node == first) {
1020:                        break;
1021:                    }
1022:                    node = node.parent;
1023:                }
1024:
1025:                if (node == null) {
1026:                    throw new NodeNotFoundException(earliest.toString());
1027:                }
1028:
1029:                return (Node[]) result.toArray(new Node[result.size()]);
1030:            }
1031:
1032:            /**
1033:             * Returns the description associated with the archive.
1034:             * @return the description
1035:             */
1036:            public String getDesc() {
1037:                return desc;
1038:            }
1039:
1040:            /** Returns the log message associated with the given revision.
1041:             *  @param version - the version to get the log message for
1042:             *  @return the log message for the version.
1043:             *  @exception - if the version does not exist for the archive.
1044:             */
1045:            public String getLog(Version version) throws NodeNotFoundException {
1046:                Node node = this .findNode(version);
1047:                if (node == null) {
1048:                    throw new NodeNotFoundException("There's no version "
1049:                            + version);
1050:                }
1051:                return node.getLog();
1052:            }
1053:
1054:            /** Returns the log message associated with the given revision.
1055:             *  @param version - the version to get the log message for
1056:             * 	@return the log message for the version.
1057:             *  @exception - if the version does not exist for the archive.
1058:             */
1059:            public String getLog(String vernum)
1060:                    throws InvalidVersionNumberException, NodeNotFoundException {
1061:                return getLog(new Version(vernum));
1062:            }
1063:
1064:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.