001: /*
002: * ====================================================================
003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012: package org.tigris.subversion.javahl;
013:
014: import java.io.File;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.io.OutputStream;
018: import java.util.ArrayList;
019:
020: import org.tmatesoft.svn.core.SVNErrorCode;
021: import org.tmatesoft.svn.core.SVNErrorMessage;
022: import org.tmatesoft.svn.core.SVNException;
023: import org.tmatesoft.svn.core.SVNLock;
024: import org.tmatesoft.svn.core.SVNRevisionProperty;
025: import org.tmatesoft.svn.core.SVNURL;
026: import org.tmatesoft.svn.core.internal.io.fs.FSRepository;
027: import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
028: import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator;
029: import org.tmatesoft.svn.core.io.SVNRepository;
030: import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
031: import org.tmatesoft.svn.core.javahl.SVNClientImpl;
032: import org.tmatesoft.svn.core.wc.SVNWCUtil;
033: import org.tmatesoft.svn.core.wc.admin.SVNAdminClient;
034: import org.tmatesoft.svn.core.wc.admin.SVNAdminEvent;
035: import org.tmatesoft.svn.core.wc.admin.SVNAdminEventAction;
036: import org.tmatesoft.svn.core.wc.admin.SVNAdminEventAdapter;
037: import org.tmatesoft.svn.core.wc.admin.SVNUUIDAction;
038:
039: /**
040: * @version 1.1.1
041: * @author TMate Software Ltd.
042: */
043: public class SVNAdmin {
044:
045: protected long cppAddr;
046: private SVNClientImpl myDelegate;
047: private SVNAdminClient mySVNAdminClient;
048:
049: /**
050: * Filesystem in a Berkeley DB
051: */
052: public static final String BDB = "bdb";
053: /**
054: * Filesystem in the filesystem
055: */
056: public static final String FSFS = "fsfs";
057:
058: public SVNAdmin() {
059: myDelegate = SVNClientImpl.newInstance();
060: }
061:
062: public void dispose() {
063: myDelegate.dispose();
064: mySVNAdminClient = null;
065: }
066:
067: /**
068: * @return Version information about the underlying native libraries.
069: */
070: public Version getVersion() {
071: return myDelegate.getVersion();
072: }
073:
074: /**
075: * create a subversion repository.
076: * @param path the path where the repository will been
077: * created.
078: * @param disableFsyncCommit disable to fsync at the commit (BDB).
079: * @param keepLog keep the log files (BDB).
080: * @param configPath optional path for user configuration files.
081: * @param fstype the type of the filesystem (BDB or FSFS)
082: * @throws ClientException throw in case of problem
083: */
084: public void create(String path, boolean disableFsyncCommit,
085: boolean keepLog, String configPath, String fstype)
086: throws ClientException {
087: if (BDB.equalsIgnoreCase(fstype)) {
088: notImplementedYet("Only " + FSFS
089: + " type of repositories are supported by "
090: + getVersion().toString());
091: }
092: try {
093: SVNRepositoryFactory.createLocalRepository(new File(path),
094: false, false);
095: if (configPath != null) {
096:
097: }
098: } catch (SVNException e) {
099: JavaHLObjectFactory.throwException(e, myDelegate);
100: }
101:
102: }
103:
104: /**
105: * deltify the revisions in the repository
106: * @param path the path to the repository
107: * @param start start revision
108: * @param end end revision
109: * @throws ClientException throw in case of problem
110: */
111: public void deltify(String path, Revision start, Revision end)
112: throws ClientException {
113: notImplementedYet();
114: }
115:
116: /**
117: * dump the data in a repository
118: * @param path the path to the repository
119: * @param dataOut the data will be outputed here
120: * @param errorOut the messages will be outputed here
121: * @param start the first revision to be dumped
122: * @param end the last revision to be dumped
123: * @param incremental the dump will be incremantal
124: * @throws ClientException throw in case of problem
125: */
126: public void dump(String path, final OutputInterface dataOut,
127: final OutputInterface errorOut, Revision start,
128: Revision end, boolean incremental) throws ClientException {
129: OutputStream os = createOutputStream(dataOut);
130: try {
131: getAdminClient().setEventHandler(
132: new SVNAdminEventAdapter() {
133: public void handleAdminEvent(
134: SVNAdminEvent event, double progress)
135: throws SVNException {
136: if (errorOut != null
137: && event.getAction() == SVNAdminEventAction.REVISION_DUMPED) {
138: try {
139: errorOut.write(event.getMessage()
140: .getBytes());
141: errorOut
142: .write(SVNTranslator.NATIVE);
143: } catch (IOException e) {
144: }
145: }
146: }
147: });
148: getAdminClient().doDump(new File(path).getAbsoluteFile(),
149: os, JavaHLObjectFactory.getSVNRevision(start),
150: JavaHLObjectFactory.getSVNRevision(end),
151: incremental, false);
152: } catch (SVNException e) {
153: try {
154: if (errorOut != null) {
155: errorOut.write(e.getErrorMessage().getFullMessage()
156: .getBytes("UTF-8"));
157: errorOut.write(SVNTranslator.NATIVE);
158: }
159: } catch (IOException e1) {
160: //
161: }
162: JavaHLObjectFactory.throwException(e, myDelegate);
163: } finally {
164: getAdminClient().setEventHandler(null);
165: }
166: }
167:
168: /**
169: * make a hot copy of the repository
170: * @param path the path to the source repository
171: * @param targetPath the path to the target repository
172: * @param cleanLogs clean the unused log files in the source
173: * repository
174: * @throws ClientException throw in case of problem
175: */
176: public void hotcopy(String path, String targetPath,
177: boolean cleanLogs) throws ClientException {
178: notImplementedYet();
179: }
180:
181: /**
182: * list all logfiles (BDB) in use or not)
183: * @param path the path to the repository
184: * @param receiver interface to receive the logfile names
185: * @throws ClientException throw in case of problem
186: */
187: public void listDBLogs(String path, MessageReceiver receiver)
188: throws ClientException {
189: notImplementedYet("Only " + FSFS
190: + " type of repositories are supported by "
191: + getVersion().toString());
192: }
193:
194: /**
195: * list unused logfiles
196: * @param path the path to the repository
197: * @param receiver interface to receive the logfile names
198: * @throws ClientException throw in case of problem
199: */
200: public void listUnusedDBLogs(String path, MessageReceiver receiver)
201: throws ClientException {
202: notImplementedYet("Only " + FSFS
203: + " type of repositories are supported by "
204: + getVersion().toString());
205: }
206:
207: /**
208: * interface to receive the messages
209: */
210: public static interface MessageReceiver {
211: /**
212: * receive one message line
213: * @param message one line of message
214: */
215: public void receiveMessageLine(String message);
216: }
217:
218: /**
219: * load the data of a dump into a repository,
220: * @param path the path to the repository
221: * @param dataInput the data input source
222: * @param messageOutput the target for processing messages
223: * @param ignoreUUID ignore any UUID found in the input stream
224: * @param forceUUID set the repository UUID to any found in the
225: * stream
226: * @param relativePath the directory in the repository, where the data
227: * in put optional.
228: * @throws ClientException throw in case of problem
229: */
230: public void load(String path, InputInterface dataInput,
231: final OutputInterface messageOutput, boolean ignoreUUID,
232: boolean forceUUID, String relativePath)
233: throws ClientException {
234: InputStream is = createInputStream(dataInput);
235: try {
236: SVNUUIDAction uuidAction = SVNUUIDAction.DEFAULT;
237: if (ignoreUUID) {
238: uuidAction = SVNUUIDAction.IGNORE_UUID;
239: } else if (forceUUID) {
240: uuidAction = SVNUUIDAction.FORCE_UUID;
241: }
242: getAdminClient().setEventHandler(
243: new SVNAdminEventAdapter() {
244:
245: private boolean myIsNodeOpened;
246:
247: public void handleAdminEvent(
248: SVNAdminEvent event, double progress)
249: throws SVNException {
250: if (messageOutput != null) {
251: try {
252: messageOutput.write(getLoadMessage(
253: event).getBytes("UTF-8"));
254: } catch (IOException e) {
255: }
256: }
257: }
258:
259: protected String getLoadMessage(
260: SVNAdminEvent event) {
261: StringBuffer message = new StringBuffer();
262: if (event.getAction() != SVNAdminEventAction.REVISION_LOAD
263: && myIsNodeOpened) {
264: message.append(" done.");
265: message.append(SVNTranslator.NATIVE);
266: myIsNodeOpened = false;
267: }
268: if (event.getAction() == SVNAdminEventAction.REVISION_LOADED) {
269: message.append(SVNTranslator.NATIVE);
270: }
271: message.append(event.getMessage());
272: message.append(SVNTranslator.NATIVE);
273: if (event.getAction() == SVNAdminEventAction.REVISION_LOADED) {
274: message.append(SVNTranslator.NATIVE);
275: }
276: myIsNodeOpened = event.getAction() != SVNAdminEventAction.REVISION_LOAD;
277: return message.toString();
278: }
279: });
280: getAdminClient().doLoad(new File(path).getAbsoluteFile(),
281: is, false, false, uuidAction, relativePath);
282: } catch (SVNException e) {
283: if (messageOutput != null) {
284: try {
285: messageOutput.write(e.getErrorMessage()
286: .getFullMessage().getBytes("UTF-8"));
287: messageOutput.write(SVNTranslator.NATIVE);
288: } catch (IOException e1) {
289: }
290: }
291: JavaHLObjectFactory.throwException(e, myDelegate);
292: } finally {
293: getAdminClient().setEventHandler(null);
294: }
295:
296: }
297:
298: /**
299: * list all open transactions in a repository
300: * @param path the path to the repository
301: * @param receiver receives one transaction name per call
302: * @throws ClientException throw in case of problem
303: */
304: public void lstxns(String path, final MessageReceiver receiver)
305: throws ClientException {
306: getAdminClient().setEventHandler(new SVNAdminEventAdapter() {
307: public void handleAdminEvent(SVNAdminEvent event,
308: double progress) throws SVNException {
309: if (receiver != null && event.getTxnName() != null) {
310: receiver.receiveMessageLine(event.getTxnName());
311: }
312: }
313: });
314: try {
315: getAdminClient().doListTransactions(
316: new File(path).getAbsoluteFile());
317: } catch (SVNException e) {
318: JavaHLObjectFactory.throwException(e, myDelegate);
319: } finally {
320: getAdminClient().setEventHandler(null);
321: }
322: }
323:
324: /**
325: * recover the berkeley db of a repository, returns youngest revision
326: * @param path the path to the repository
327: * @throws ClientException throw in case of problem
328: */
329: public long recover(String path) throws ClientException {
330: notImplementedYet("Only " + FSFS
331: + " type of repositories are supported by "
332: + getVersion().toString());
333: return -1;
334: }
335:
336: /**
337: * remove open transaction in a repository
338: * @param path the path to the repository
339: * @param transactions the transactions to be removed
340: * @throws ClientException throw in case of problem
341: */
342: public void rmtxns(String path, String[] transactions)
343: throws ClientException {
344: try {
345: getAdminClient().doRemoveTransactions(
346: new File(path).getAbsoluteFile(), transactions);
347: } catch (SVNException e) {
348: JavaHLObjectFactory.throwException(e, myDelegate);
349: }
350: }
351:
352: /**
353: * set the log message of a revision
354: * @param path the path to the repository
355: * @param rev the revision to be changed
356: * @param message the message to be set
357: * @param bypassHooks if to bypass all repository hooks
358: * @throws ClientException throw in case of problem
359: */
360: public void setLog(String path, Revision rev, String message,
361: boolean bypassHooks) throws ClientException {
362: try {
363: SVNRepository repository = SVNRepositoryFactory
364: .create(SVNURL.fromFile(new File(path)
365: .getAbsoluteFile()));
366: ((FSRepository) repository)
367: .setRevisionPropertyValue(JavaHLObjectFactory
368: .getSVNRevision(rev).getNumber(),
369: SVNRevisionProperty.LOG, message,
370: bypassHooks);
371: } catch (SVNException e) {
372: JavaHLObjectFactory.throwException(e, myDelegate);
373: }
374: }
375:
376: /**
377: * verify the repository
378: * @param path the path to the repository
379: * @param messageOut the receiver of all messages
380: * @param start the first revision
381: * @param end the last revision
382: * @throws ClientException throw in case of problem
383: */
384: public void verify(String path, final OutputInterface messageOut,
385: Revision start, Revision end) throws ClientException {
386: try {
387: getAdminClient().setEventHandler(
388: new SVNAdminEventAdapter() {
389: public void handleAdminEvent(
390: SVNAdminEvent event, double progress)
391: throws SVNException {
392: if (messageOut != null
393: && event.getAction() == SVNAdminEventAction.REVISION_DUMPED) {
394: try {
395: messageOut.write(event.getMessage()
396: .getBytes());
397: messageOut
398: .write(SVNTranslator.NATIVE);
399: } catch (IOException e) {
400: }
401: }
402: }
403: });
404: getAdminClient().doVerify(new File(path).getAbsoluteFile(),
405: JavaHLObjectFactory.getSVNRevision(start),
406: JavaHLObjectFactory.getSVNRevision(end));
407: } catch (SVNException e) {
408: try {
409: if (messageOut != null) {
410: messageOut.write(e.getErrorMessage()
411: .getFullMessage().getBytes("UTF-8"));
412: messageOut.write(SVNTranslator.NATIVE);
413: }
414: } catch (IOException e1) {
415: //
416: }
417: JavaHLObjectFactory.throwException(e, myDelegate);
418: } finally {
419: getAdminClient().setEventHandler(null);
420: }
421: }
422:
423: /**
424: * list all locks in the repository
425: * @param path the path to the repository
426: * @throws ClientException throw in case of problem
427: * @since 1.2
428: */
429: public Lock[] lslocks(String path) throws ClientException {
430: final ArrayList locks = new ArrayList();
431: getAdminClient().setEventHandler(new SVNAdminEventAdapter() {
432: public void handleAdminEvent(SVNAdminEvent event,
433: double progress) throws SVNException {
434: if (event.getAction() == SVNAdminEventAction.LOCK_LISTED) {
435: SVNLock svnLock = event.getLock();
436: Lock lock = JavaHLObjectFactory.createLock(svnLock);
437: locks.add(lock);
438: }
439: }
440: });
441:
442: try {
443: getAdminClient().doListLocks(
444: new File(path).getAbsoluteFile());
445: } catch (SVNException e) {
446: JavaHLObjectFactory.throwException(e, myDelegate);
447: } finally {
448: getAdminClient().setEventHandler(null);
449: }
450:
451: return (Lock[]) locks.toArray(new Lock[locks.size()]);
452: }
453:
454: /**
455: * remove multiple locks from the repository
456: * @param path the path to the repository
457: * @param locks the name of the locked items
458: * @throws ClientException throw in case of problem
459: * @since 1.2
460: */
461: public void rmlocks(String path, String[] locks)
462: throws ClientException {
463: try {
464: getAdminClient().doRemoveLocks(
465: new File(path).getAbsoluteFile(), locks);
466: } catch (SVNException e) {
467: JavaHLObjectFactory.throwException(e, myDelegate);
468: } finally {
469: getAdminClient().setEventHandler(null);
470: }
471: }
472:
473: private void notImplementedYet() throws ClientException {
474: notImplementedYet(null);
475: }
476:
477: private void notImplementedYet(String message)
478: throws ClientException {
479: SVNErrorMessage err = SVNErrorMessage
480: .create(
481: SVNErrorCode.UNSUPPORTED_FEATURE,
482: message == null ? "Requested SVNAdmin functionality is not yet implemented"
483: : message);
484: JavaHLObjectFactory.throwException(new SVNException(err),
485: myDelegate);
486: }
487:
488: protected SVNAdminClient getAdminClient() {
489: if (mySVNAdminClient == null) {
490: mySVNAdminClient = new SVNAdminClient(SVNWCUtil
491: .createDefaultAuthenticationManager(), SVNWCUtil
492: .createDefaultOptions(true));
493: }
494: return mySVNAdminClient;
495: }
496:
497: private static OutputStream createOutputStream(
498: final OutputInterface dataOut) {
499: if (dataOut == null) {
500: return SVNFileUtil.DUMMY_OUT;
501: }
502: return new OutputStream() {
503: public void write(int b) throws IOException {
504: dataOut.write(new byte[] { (byte) (b & 0xFF) });
505: }
506:
507: public void write(byte[] b) throws IOException {
508: dataOut.write(b);
509: }
510:
511: public void close() throws IOException {
512: dataOut.close();
513: }
514:
515: public void write(byte[] b, int off, int len)
516: throws IOException {
517: byte[] copy = new byte[len];
518: System.arraycopy(b, off, copy, 0, len);
519: dataOut.write(copy);
520: }
521: };
522: }
523:
524: private static InputStream createInputStream(
525: final InputInterface dataIn) {
526: if (dataIn == null) {
527: return SVNFileUtil.DUMMY_IN;
528: }
529: return new InputStream() {
530:
531: public int read() throws IOException {
532: byte[] b = new byte[1];
533: int r = dataIn.read(b);
534: if (r <= 0) {
535: return -1;
536: }
537: return b[0];
538: }
539:
540: public void close() throws IOException {
541: dataIn.close();
542: }
543:
544: public int read(byte[] b, int off, int len)
545: throws IOException {
546: byte[] copy = new byte[len];
547: int realLen = dataIn.read(copy);
548: if (realLen <= 0) {
549: return realLen;
550: }
551: System.arraycopy(copy, 0, b, off, realLen);
552: return realLen;
553: }
554:
555: public int read(byte[] b) throws IOException {
556: return dataIn.read(b);
557: }
558: };
559: }
560:
561: }
|