/* Copyright 2004-2014 Jim Voris
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qumasoft.server;
import com.qumasoft.qvcslib.AbstractProjectProperties;
import com.qumasoft.qvcslib.AccessList;
import com.qumasoft.qvcslib.ArchiveAttributes;
import com.qumasoft.qvcslib.CommentPrefixProperties;
import com.qumasoft.qvcslib.Compressor;
import com.qumasoft.qvcslib.ExtensionAttributeProperties;
import com.qumasoft.qvcslib.LogFileHeaderInfo;
import com.qumasoft.qvcslib.QVCSException;
import com.qumasoft.qvcslib.RevisionHeader;
import com.qumasoft.qvcslib.Utility;
import com.qumasoft.qvcslib.ZlibCompressor;
import com.qumasoft.qvcslib.commandargs.CreateArchiveCommandArgs;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Create an archive.
* @author Jim Voris
*/
class LogFileOperationCreateArchive extends AbstractLogFileOperation {
// Create our logger object
private static final Logger LOGGER = Logger.getLogger("com.qumasoft.server");
private final AccessList accessList;
private final String filename;
private final String userName;
private final CreateArchiveCommandArgs commandLineArgs;
private final String archiveDescription;
private final boolean lockFlag;
private RandomAccessFile newArchiveStream;
private final AbstractProjectProperties projectProperties;
private ArchiveAttributes archiveAttributes;
private final String workfileName;
private final String commentPrefix;
/**
* Creates a new instance of LogFileOperationCreateArchive.
* @param args arguments for the operation. a[0] is the logfileImpl; a[1] is filename; a[2] is the project properties; a[3] are the command arguments object.
*/
LogFileOperationCreateArchive(Object[] args) {
super(args, (LogFileImpl) args[0]);
filename = (String) args[1];
projectProperties = (AbstractProjectProperties) args[2];
// <editor-fold>
commandLineArgs = (CreateArchiveCommandArgs) args[3];
// </editor-fold>
userName = commandLineArgs.getUserName();
archiveDescription = commandLineArgs.getArchiveDescription();
lockFlag = commandLineArgs.getLockFlag();
workfileName = commandLineArgs.getWorkfileName();
commentPrefix = getCommentPrefix();
accessList = projectProperties.getInitialArchiveAccessList();
}
@Override
public boolean execute() throws QVCSException {
boolean retVal = false;
// Make sure the creator is on the access list.
accessList.addUser(commandLineArgs.getUserName());
if (commandLineArgs.getAttributes() == null) {
// Get the attributes based on file extension.
archiveAttributes = ExtensionAttributeProperties.getInstance().getAttributes(workfileName);
} else {
// The user defined the attributes for us.
archiveAttributes = commandLineArgs.getAttributes();
}
try {
// Make sure a valid archive file does not already exist.
if (getLogFileImpl().getFile().exists()) {
if (getLogFileImpl().isValidArchive()) {
throw new QVCSException("Archive already exists for " + getLogFileImpl().getFile().getAbsolutePath());
}
}
// Create the archive file.
newArchiveStream = new java.io.RandomAccessFile(getLogFileImpl().getTempFile(), "rw");
// And populate it with data.
createNewLogfileCreatingNewTrunkTip();
retVal = true;
} catch (QVCSException | IOException e) {
LOGGER.log(Level.WARNING, "LogFileOperationCreateArchive exception: " + e.toString() + ": " + e.getMessage());
LOGGER.log(Level.WARNING, Utility.expandStackTraceToString(e));
retVal = false;
} finally {
try {
if (newArchiveStream != null) {
newArchiveStream.close();
}
} catch (IOException e) {
LOGGER.log(Level.WARNING, Utility.expandStackTraceToString(e));
retVal = false;
} finally {
newArchiveStream = null;
}
}
// Remove any old archives.
if (retVal) {
// It is safe to delete these since we don't have a valid archive file.
getLogFileImpl().getOldFile().delete();
getLogFileImpl().getFile().delete();
if (getLogFileImpl().getTempFile().renameTo(getLogFileImpl().getFile())) {
retVal = true;
} else {
throw new QVCSException("Unable to rename temporary copy of archive for " + getLogFileImpl().getShortWorkfileName());
}
} else {
getLogFileImpl().getTempFile().delete();
}
return retVal;
}
private void createNewLogfileCreatingNewTrunkTip() throws QVCSException, IOException {
// We need to know how big the origin workfile is for the header.
File workfile = new File(filename);
Date now = new Date();
// Create the archive header
LogFileHeaderInfo archiveHeader = new LogFileHeaderInfo();
populateArchiveHeader(archiveHeader, workfile, now);
getLogFileImpl().setHeaderInfo(archiveHeader);
// Increment the number of revisions.
archiveHeader.getLogFileHeader().incrementRevisionCount();
// Increment the lock count if there is lock checking for this archive
if (lockFlag && archiveHeader.getLogFileHeader().attributes().getIsCheckLock()) {
archiveHeader.getLogFileHeader().incrementLockCount();
}
// Write the header.
archiveHeader.write(newArchiveStream);
// Create the revision header for this new revision.
RevisionHeader newRevisionHeader = new RevisionHeader(new AccessList(archiveHeader.getAccessList()),
new AccessList(archiveHeader.getModifierList()));
newRevisionHeader.setCreator(userName);
if (commandLineArgs.getCheckInTimestamp() != null) {
newRevisionHeader.setCheckInDate(commandLineArgs.getCheckInTimestamp());
} else {
newRevisionHeader.setCheckInDate(now);
}
newRevisionHeader.setEditDate(commandLineArgs.getInputfileTimeStamp());
newRevisionHeader.setRevisionDescription("Initial Revision");
newRevisionHeader.setIsTip(true);
if (lockFlag && archiveHeader.getLogFileHeader().attributes().getIsCheckLock()) {
newRevisionHeader.setIsLocked(true);
newRevisionHeader.setLocker(userName);
}
newRevisionHeader.setMajorNumber(1);
newRevisionHeader.setMinorNumber(0);
Compressor compressor = new ZlibCompressor();
newRevisionHeader.setRevisionSize(getCompressedRevisionSizeForWorkfile(workfile, compressor));
newRevisionHeader.setIsCompressed(compressor.getBufferIsCompressedFlag());
newRevisionHeader.write(newArchiveStream);
// Copy the workfile as the first revision.
copyFromOneOpenFileToAnotherOpenFile(compressor.getCompressedStream(), newArchiveStream, newRevisionHeader.getRevisionSize());
}
private void populateArchiveHeader(LogFileHeaderInfo header, File workfile, Date now) throws QVCSException {
header.setAccessList(accessList.getAccessListAsCommaSeparatedString());
header.setModifierList(accessList.getAccessListAsCommaSeparatedString());
header.setCommentPrefix(commentPrefix);
header.setOwner(userName);
// If no description is supplied, we'll just use the short workfile name
// as the module description.
if ((archiveDescription == null) || (archiveDescription.length() == 0)) {
header.setModuleDescription(getLogFileImpl().getShortWorkfileName());
} else {
header.setModuleDescription(archiveDescription);
}
header.getLogFileHeader().getMajorNumber().setValue(1);
header.getLogFileHeader().getMinorNumber().setValue(0);
// Set this file's attributes.
header.getLogFileHeader().setAttributes(archiveAttributes);
// Set the stuff that goes in the supplemental info.
header.setWorkfileName(workfileName);
header.getSupplementalHeaderInfo().setLastWorkfileSize(workfile.length());
header.getSupplementalHeaderInfo().setLastArchiveUpdateDate(now);
header.getSupplementalHeaderInfo().setLastModifierIndex(accessList.userToIndex(userName));
header.getSupplementalHeaderInfo().setFileID(FileIDManager.getInstance().getNewFileID());
}
private String getCommentPrefix() {
String derivedCommentPrefix = commandLineArgs.getCommentPrefix();
if ((derivedCommentPrefix != null) && (derivedCommentPrefix.length() > 0)) {
return derivedCommentPrefix;
} else {
derivedCommentPrefix = CommentPrefixProperties.getInstance().getCommentPrefix(workfileName);
}
return derivedCommentPrefix;
}
}