/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.netbeans.lib.cvsclient.command;
import java.io.UnsupportedEncodingException;
import org.netbeans.lib.cvsclient.ClientServices;
import org.netbeans.lib.cvsclient.connection.AuthenticationException;
import org.netbeans.lib.cvsclient.event.BinaryMessageEvent;
import org.netbeans.lib.cvsclient.event.EnhancedMessageEvent;
import org.netbeans.lib.cvsclient.event.EventManager;
import org.netbeans.lib.cvsclient.event.MessageEvent;
import org.netbeans.lib.cvsclient.event.TerminationEvent;
/**
* A class that provides common functionality for many of the CVS command that send similar sequences of requests.
*
* @author Robert Greig
*/
public abstract class BuildableCommand extends Command {
/**
* An implementation of Builder interface that constructs a FileContainerInfo object from the server's output..
*/
protected Builder builder;
private final StringBuffer taggedLineBuffer = new StringBuffer();
/**
* A boolean value indicating if the user has used the setBuilder() method.
*/
private boolean builderSet;
/**
* Execute a command. This implementation sends a Root request, followed by as many Directory and Entry requests as is required by the
* recurse setting and the file arguments that have been set. Subclasses should call this first, and tag on the end of the requests list
* any further requests and, finally, the actually request that does the command (e.g.
*
* <pre>
* update
* </pre>
*
* ,
*
* <pre>
* status
* </pre>
*
* etc.)
*
* @param client
* the client services object that provides any necessary services to this command, including the ability to actually process
* all the requests
* @throws CommandException
* if an error occurs executing the command
*/
@Override
public void execute(ClientServices client, EventManager eventManager) throws CommandException, AuthenticationException {
super.execute(client, eventManager);
if (builder == null && !isBuilderSet()) {
builder = createBuilder(eventManager);
}
}
/**
* Method that is called while the command is being executed. Descendants can override this method to return a Builder instance that
* will parse the server's output and create data structures.
*/
public Builder createBuilder(EventManager eventManager) {
return null;
}
@Override
public void messageSent(BinaryMessageEvent e) {
super.messageSent(e);
if (builder == null) {
return;
}
if (builder instanceof BinaryBuilder) { // XXX assert it?
BinaryBuilder binaryBuilder = (BinaryBuilder) builder;
binaryBuilder.parseBytes(e.getMessage(), e.getMessageLength());
}
}
@Override
public void messageSent(MessageEvent e) {
super.messageSent(e);
if (builder == null) {
return;
}
if (e instanceof EnhancedMessageEvent) {
EnhancedMessageEvent eEvent = (EnhancedMessageEvent) e;
builder.parseEnhancedMessage(eEvent.getKey(), eEvent.getValue());
return;
}
if (e.isTagged()) {
String message = MessageEvent.parseTaggedMessage(taggedLineBuffer, e.getMessage());
if (message != null) {
builder.parseLine(message, false);
taggedLineBuffer.setLength(0);
}
} else {
if (taggedLineBuffer.length() > 0) {
builder.parseLine(taggedLineBuffer.toString(), false);
taggedLineBuffer.setLength(0);
}
// #67337 do not interpret piped data using platform default encoding
// UTF-8 causes problems as raw data (non UTf-8) can contain confusing sequences
// use safe encoding that does not interpret byte sequences
if (builder instanceof PipedFilesBuilder && e.isError() == false) {
try {
String iso88591 = new String(e.getRawData(), "ISO-8859-1");
builder.parseLine(iso88591, e.isError());
} catch (UnsupportedEncodingException e1) {
assert false;
}
} else {
builder.parseLine(e.getMessage(), e.isError());
}
}
}
/**
* Returns whether the builder is set.
*/
protected boolean isBuilderSet() {
return builderSet;
}
/**
* Used for setting user-defined builder. Can be also set null, in that case the builder mechanism is not used at all.
*/
public void setBuilder(Builder builder) {
this.builder = builder;
builderSet = true;
}
/**
* Called when server responses with "ok" or "error", (when the command finishes).
*/
@Override
public void commandTerminated(TerminationEvent e) {
if (builder == null) {
return;
}
if (taggedLineBuffer.length() > 0) {
builder.parseLine(taggedLineBuffer.toString(), false);
taggedLineBuffer.setLength(0);
}
builder.outputDone();
}
}