Merge pull request #10569 from tdonohue/remove_unused_sword_client_8x

[Port dspace-8_x] Remove unused, unmaintained SWORD v1 client code
This commit is contained in:
Tim Donohue
2025-04-08 06:58:43 -05:00
committed by GitHub
20 changed files with 0 additions and 4751 deletions

View File

@@ -1,463 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.logging.log4j.Logger;
import org.purl.sword.base.ChecksumUtils;
import org.purl.sword.base.DepositResponse;
import org.purl.sword.base.HttpHeaders;
import org.purl.sword.base.ServiceDocument;
import org.purl.sword.base.SwordValidationInfo;
import org.purl.sword.base.UnmarshallException;
/**
* This is an example Client implementation to demonstrate how to connect to a
* SWORD server. The client supports BASIC HTTP Authentication. This can be
* initialised by setting a username and password.
*
* @author Neil Taylor
*/
public class Client implements SWORDClient {
/**
* The status field for the response code from the recent network access.
*/
private Status status;
/**
* The name of the server to contact.
*/
private String server;
/**
* The port number for the server.
*/
private int port;
/**
* Specifies if the network access should use HTTP authentication.
*/
private boolean doAuthentication;
/**
* The username to use for Basic Authentication.
*/
private String username;
/**
* User password that is to be used.
*/
private String password;
/**
* The userAgent to identify this application.
*/
private String userAgent;
/**
* The client that is used to send data to the specified server.
*/
private final DefaultHttpClient client;
/**
* The default connection timeout. This can be modified by using the
* setSocketTimeout method.
*/
public static final int DEFAULT_TIMEOUT = 20000;
/**
* Logger.
*/
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(Client.class);
/**
* Create a new Client. The client will not use authentication by default.
*/
public Client() {
client = new DefaultHttpClient();
HttpParams params = client.getParams();
params.setParameter("http.socket.timeout",
Integer.valueOf(DEFAULT_TIMEOUT));
HttpHost proxyHost = (HttpHost) params
.getParameter(ConnRoutePNames.DEFAULT_PROXY); // XXX does this really work?
log.debug("proxy host: " + proxyHost.getHostName());
log.debug("proxy port: " + proxyHost.getPort());
doAuthentication = false;
}
/**
* Initialise the server that will be used to send the network access.
*
* @param server server address/hostname
* @param port server port
*/
public void setServer(String server, int port) {
this.server = server;
this.port = port;
}
/**
* Set the user credentials that will be used when making the access to the
* server.
*
* @param username The username.
* @param password The password.
*/
public void setCredentials(String username, String password) {
this.username = username;
this.password = password;
doAuthentication = true;
}
/**
* Set the basic credentials. You must have previously set the server and
* port using setServer.
*
* @param username The username.
* @param password The password.
*/
private void setBasicCredentials(String username, String password) {
log.debug("server: " + server + " port: " + port + " u: '" + username
+ "' p '" + password + "'");
client.getCredentialsProvider().setCredentials(new AuthScope(server, port),
new UsernamePasswordCredentials(username, password));
}
/**
* Set a proxy that should be used by the client when trying to access the
* server. If this is not set, the client will attempt to make a direct
* direct connection to the server. The port is set to 80.
*
* @param host The hostname.
*/
public void setProxy(String host) {
setProxy(host, 80);
}
/**
* Set a proxy that should be used by the client when trying to access the
* server. If this is not set, the client will attempt to make a direct
* direct connection to the server.
*
* @param host The name of the host.
* @param port The port.
*/
public void setProxy(String host, int port) {
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost(host, port)); // XXX does this really work?
}
/**
* Clear the proxy setting.
*/
public void clearProxy() {
client.getParams().removeParameter(ConnRoutePNames.DEFAULT_PROXY); // XXX does this really work?
}
/**
* Clear any user credentials that have been set for this client.
*/
public void clearCredentials() {
client.getCredentialsProvider().clear();
doAuthentication = false;
}
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
}
/**
* Set the connection timeout for the socket.
*
* @param milliseconds The time, expressed as a number of milliseconds.
*/
public void setSocketTimeout(int milliseconds) {
client.getParams().setParameter("http.socket.timeout",
Integer.valueOf(milliseconds));
}
/**
* Retrieve the service document. The service document is located at the
* specified URL. This calls getServiceDocument(url,onBehalfOf).
*
* @param url The location of the service document.
* @return The ServiceDocument, or <code>null</code> if there was a
* problem accessing the document. e.g. invalid access.
* @throws SWORDClientException If there is an error accessing the resource.
*/
public ServiceDocument getServiceDocument(String url)
throws SWORDClientException {
return getServiceDocument(url, null);
}
/**
* Retrieve the service document. The service document is located at the
* specified URL. This calls getServiceDocument(url,onBehalfOf).
*
* @param url The location of the service document.
* @return The ServiceDocument, or <code>null</code> if there was a
* problem accessing the document. e.g. invalid access.
* @throws SWORDClientException If there is an error accessing the resource.
*/
public ServiceDocument getServiceDocument(String url, String onBehalfOf)
throws SWORDClientException {
URL serviceDocURL = null;
try {
serviceDocURL = new URL(url);
} catch (MalformedURLException e) {
// Try relative URL
URL baseURL = null;
try {
baseURL = new URL("http", server, Integer.valueOf(port), "/");
serviceDocURL = new URL(baseURL, (url == null) ? "" : url);
} catch (MalformedURLException e1) {
// No dice, can't even form base URL...
throw new SWORDClientException(url + " is not a valid URL ("
+ e1.getMessage()
+ "), and could not form a relative one from: "
+ baseURL + " / " + url, e1);
}
}
HttpGet httpget = new HttpGet(serviceDocURL.toExternalForm());
if (doAuthentication) {
// this does not perform any check on the username password. It
// relies on the server to determine if the values are correct.
setBasicCredentials(username, password);
}
Properties properties = new Properties();
if (containsValue(onBehalfOf)) {
log.debug("Setting on-behalf-of: " + onBehalfOf);
httpget.addHeader(url, url);
httpget.addHeader(HttpHeaders.X_ON_BEHALF_OF, onBehalfOf);
properties.put(HttpHeaders.X_ON_BEHALF_OF, onBehalfOf);
}
if (containsValue(userAgent)) {
log.debug("Setting userAgent: " + userAgent);
httpget.addHeader(HttpHeaders.USER_AGENT, userAgent);
properties.put(HttpHeaders.USER_AGENT, userAgent);
}
ServiceDocument doc = null;
try {
HttpResponse response = client.execute(httpget);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
// store the status code
status = new Status(statusCode, statusLine.getReasonPhrase());
if (status.getCode() == HttpStatus.SC_OK) {
String message = readResponse(response.getEntity().getContent());
log.debug("returned message is: " + message);
doc = new ServiceDocument();
lastUnmarshallInfo = doc.unmarshall(message, properties);
} else {
throw new SWORDClientException(
"Received error from service document request: "
+ status);
}
} catch (IOException ioex) {
throw new SWORDClientException(ioex.getMessage(), ioex);
} catch (UnmarshallException uex) {
throw new SWORDClientException(uex.getMessage(), uex);
} finally {
httpget.releaseConnection();
}
return doc;
}
private SwordValidationInfo lastUnmarshallInfo;
/**
* @return SWORD validation info
*/
public SwordValidationInfo getLastUnmarshallInfo() {
return lastUnmarshallInfo;
}
/**
* Post a file to the server. The different elements of the post are encoded
* in the specified message.
*
* @param message The message that contains the post information.
* @throws SWORDClientException if there is an error during the post operation.
*/
public DepositResponse postFile(PostMessage message)
throws SWORDClientException {
if (message == null) {
throw new SWORDClientException("Message cannot be null.");
}
HttpPost httppost = new HttpPost(message.getDestination());
if (doAuthentication) {
setBasicCredentials(username, password);
}
DepositResponse response = null;
String messageBody = "";
try {
if (message.isUseMD5()) {
String md5 = ChecksumUtils.generateMD5(message.getFilepath());
if (message.getChecksumError()) {
md5 = "1234567890";
}
log.debug("checksum error is: " + md5);
if (md5 != null) {
httppost.addHeader(HttpHeaders.CONTENT_MD5, md5);
}
}
String filename = message.getFilename();
if (!"".equals(filename)) {
httppost.addHeader(HttpHeaders.CONTENT_DISPOSITION,
" filename=" + filename);
}
if (containsValue(message.getSlug())) {
httppost.addHeader(HttpHeaders.SLUG, message.getSlug());
}
if (message.getCorruptRequest()) {
// insert a header with an invalid boolean value
httppost.addHeader(HttpHeaders.X_NO_OP, "Wibble");
} else {
httppost.addHeader(HttpHeaders.X_NO_OP, Boolean
.toString(message.isNoOp()));
}
httppost.addHeader(HttpHeaders.X_VERBOSE, Boolean
.toString(message.isVerbose()));
String packaging = message.getPackaging();
if (packaging != null && packaging.length() > 0) {
httppost.addHeader(HttpHeaders.X_PACKAGING, packaging);
}
String onBehalfOf = message.getOnBehalfOf();
if (containsValue(onBehalfOf)) {
httppost.addHeader(HttpHeaders.X_ON_BEHALF_OF, onBehalfOf);
}
String userAgent = message.getUserAgent();
if (containsValue(userAgent)) {
httppost.addHeader(HttpHeaders.USER_AGENT, userAgent);
}
FileEntity requestEntity = new FileEntity(
new File(message.getFilepath()),
ContentType.create(message.getFiletype()));
httppost.setEntity(requestEntity);
HttpResponse httpResponse = client.execute(httppost);
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
status = new Status(statusCode, statusLine.getReasonPhrase());
log.info("Checking the status code: " + status.getCode());
if (status.getCode() == HttpStatus.SC_ACCEPTED
|| status.getCode() == HttpStatus.SC_CREATED) {
messageBody = readResponse(httpResponse.getEntity().getContent());
response = new DepositResponse(status.getCode());
response.setLocation(httpResponse.getFirstHeader("Location").getValue());
// added call for the status code.
lastUnmarshallInfo = response.unmarshall(messageBody, new Properties());
} else {
messageBody = readResponse(httpResponse.getEntity().getContent());
response = new DepositResponse(status.getCode());
response.unmarshallErrorDocument(messageBody);
}
return response;
} catch (NoSuchAlgorithmException nex) {
throw new SWORDClientException("Unable to use MD5. "
+ nex.getMessage(), nex);
} catch (IOException ioex) {
throw new SWORDClientException(ioex.getMessage(), ioex);
} catch (UnmarshallException uex) {
throw new SWORDClientException(uex.getMessage() + "(<pre>" + messageBody + "</pre>)", uex);
} finally {
httppost.releaseConnection();
}
}
/**
* Read a response from the stream and return it as a string.
*
* @param stream The stream that contains the response.
* @return The string extracted from the screen.
* @throws UnsupportedEncodingException
* @throws IOException A general class of exceptions produced by failed or interrupted I/O
* operations.
*/
private String readResponse(InputStream stream)
throws UnsupportedEncodingException, IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream, "UTF-8"));
String line = null;
StringBuffer buffer = new StringBuffer();
while ((line = reader.readLine()) != null) {
buffer.append(line);
buffer.append("\n");
}
return buffer.toString();
}
/**
* Return the status information that was returned from the most recent
* request sent to the server.
*
* @return The status code returned from the most recent access.
*/
public Status getStatus() {
return status;
}
/**
* Check to see if the specified item contains a non-empty string.
*
* @param item The string to check.
* @return True if the string is not null and has a length greater than 0
* after any whitespace is trimmed from the start and end.
* Otherwise, false.
*/
private boolean containsValue(String item) {
return ((item != null) && (item.trim().length() > 0));
}
}

View File

@@ -1,40 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Hold general constants for the client.
*
* @author Neil Taylor
*/
public class ClientConstants {
/**
* Current software version.
*/
public static final String CLIENT_VERSION = "1.1";
/**
* the name of this application
*/
public static final String SERVICE_NAME = "CASIS Test Client";
/**
* the name of this application
*/
public static final String NOT_DEFINED_TEXT = "Not defined";
/**
* The logging property file.
*/
public static final String LOGGING_PROPERTY_FILE = "log4j.properties";
/**
* Default constructor
*/
private ClientConstants() { }
}

View File

@@ -1,116 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Entry point for the SWORD Demonstration Client. This will parse the list of
* command line options and load either a Command Line client or a GUI client.
*
* @author Neil Taylor
*/
public class ClientFactory {
/**
* Generate a string that specifies the command line options for this
* program.
*
* @return A list of the options for this program.
*/
public static String usage() {
StringBuilder buffer = new StringBuilder();
buffer.append("swordclient: version ");
buffer.append(ClientConstants.CLIENT_VERSION);
buffer.append("\n");
buffer.append("GUI Mode: ");
buffer.append("swordclient [-gui] [-nocapture]");
buffer.append("\n\n");
buffer.append("Command Mode: Service - Request a Service Document\n");
buffer.append("swordclient -cmd -t service [user-options] [proxy-options] -href url [-onBehalfOf name] ");
buffer.append("\n\n");
buffer.append("Command Mode: Post - Post a file to a remote service.\n");
buffer.append("swordclient -cmd -t post [user-options] [proxy-options] [post-options] \n");
buffer.append(" [-file file] [-filetype type] [-onBehalfOf name]");
buffer.append("\n\n");
buffer.append("Command Mode: MultiPost - Post a file to multiple remote services.\n");
buffer.append("swordclient -cmd -t multipost [user-options] [proxy-options] [post-options] \n");
buffer.append(" [-dest dest]");
buffer.append("\n\n");
buffer.append("User options: \n");
buffer.append(" -u username Specify a username to access the remote service.\n");
buffer.append(" -p password Specify a password to access the remote service.\n");
buffer.append(" Required if -u option is used.");
buffer.append("\n\n");
buffer.append("Proxy options: \n");
buffer.append(" -host host Hostname of a proxy, wwwproxy.aber.ac.uk.\n");
buffer.append(" -port port Proxy port number, e.g. 8080.\n");
buffer.append("\n\n");
buffer.append("Post options: \n");
buffer.append(" -noOp Specified to indicate that the post is a test operation.\n");
buffer.append(" -md5 Use an MD5 checksum in the message header.\n");
buffer.append(" -checksumError Mis-calculate the file checksum for server test purposes.\n");
buffer.append(" -formatNamespace ns The format namespace value.\n");
buffer.append(" -slug name The slug value.\n");
buffer.append(" -verbose Request a verbose response from the server.\n");
buffer.append("\n\n");
buffer.append("Other options: \n");
buffer.append(" -help Show this message.\n");
buffer.append(" -t type The type of operation: service, post or multipost.\n");
buffer.append(" -href url The URL for the service or post document.\n");
buffer.append(" Required for service. The post and multipost operations \n");
buffer.append(" will prompt you if the value is not provided.\n");
buffer.append(" -filetype type The filetype, e.g. application/zip. The post and multipost\n");
buffer.append(" will prompt you for the value if it is not provided.\n");
buffer.append(" -onBehalfOf name Specify this parameter to set the On Behalf Of value.\n");
buffer.append(" -dest dest Specify the destination for a deposit. This can be repeated\n");
buffer.append(" multiple times. The format is: \n");
buffer.append(" <username>[<onbehalfof>]:<password>@<href>\n");
buffer.append(" e.g. sword[nst]:swordpass@http://sword.aber.ac.uk/post/\n");
buffer.append(" nst:pass@http://sword.aber.ac.uk/post\n");
buffer.append(" -nocapture Do not capture System.out and System.err to a debug panel\n");
buffer.append(" in the GUI panel.");
return buffer.toString();
}
/**
* Create a client. If GUI mode is set, a GUI client is created. Otherwise,
* a command line client is created.
*
* @param options The list of options extracted from the command line.
* @return A new client.
*/
public ClientType createClient(ClientOptions options) {
return new CmdClient();
}
/**
* Start the application and determine which client should be loaded. The
* application currently has two modes: GUI and client. The GUI mode is the
* default option.
*
* @param args the command line arguments given
*/
public static void main(String[] args) {
ClientFactory factory = new ClientFactory();
ClientOptions options = new ClientOptions();
if (options.parseOptions(args)) {
ClientType client = factory.createClient(options);
client.run(options);
} else {
System.out.println(usage());
}
}
}

View File

@@ -1,605 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* List of options that are parsed from the command line.
*
* @author Neil Taylor
*/
public class ClientOptions {
/**
* Label for the service operation.
*/
public static final String TYPE_SERVICE = "service";
/**
* Label for the post operation.
*/
public static final String TYPE_POST = "post";
/**
* Label for the multipost operation.
*/
public static final String TYPE_MULTI_POST = "multipost";
/**
* The access type.
*/
private String accessType = null;
/**
* Proxy host name.
*/
private String proxyHost = null;
/**
* Proxy host port.
*/
private int proxyPort = 8080;
/**
* Username to access the service/post server.
*/
private String username = null;
/**
* Password to access the service/post server.
*/
private String password = null;
/**
* HREF of the server to access.
*/
private String href = null;
/**
* Filename to post.
*/
private String filename = null;
/**
* File type.
*/
private String filetype = null;
/**
* Specifies that the output streams are not to be captured by the GUI client.
*/
private boolean noCapture = false;
/**
* SLUG Header field.
*/
private String slug = null;
/**
* NoOp, used to indicate an operation on the server that does not
* require the file to be stored.
*/
private boolean noOp = false;
/**
* Request verbose output from the server.
*/
private boolean verbose = false;
/**
* OnBehalfOf user id.
*/
private String onBehalfOf = null;
/**
* Format namespace to be used for the posted file.
*/
private String formatNamespace = null;
/**
* Introduce a checksum error. This is used to simulate an error with the
* MD5 value.
*/
private boolean checksumError = false;
/**
* Logger.
*/
private static final Logger log = LogManager.getLogger();
/**
* List of multiple destination items. Used if the mode is set to multipost.
*/
private final List<PostDestination> multiPost = new ArrayList<>();
/**
* Pattern string to extract the data from a destination parameter in multipost mode.
*/
private static final Pattern MULTI_PATTERN
= Pattern.compile("(.*?)(\\[(.*?)\\]) {0,1}(:(.*)) {0,1}@(http://.*)");
/**
* Flag that indicates if the GUI mode has been set. This is
* true by default.
*/
private boolean guiMode = true;
/**
* Flat that indicates if the MD5 option has been selected. This
* is true by default.
*/
private boolean md5 = false;
/**
* Parse the list of options contained in the specified array.
*
* @param args The array of options.
* @return True if the options were parsed successfully.
*/
public boolean parseOptions(String[] args) {
Options options = new Options();
options.addOption(Option.builder().longOpt("md5").build())
.addOption(Option.builder().longOpt("noOp").build())
.addOption(Option.builder().longOpt("verbose").build())
.addOption(Option.builder().longOpt("cmd").build())
.addOption(Option.builder().longOpt("gui").build())
.addOption(Option.builder().longOpt("help").build())
.addOption(Option.builder().longOpt("nocapture").build());
Option option;
option = Option.builder().longOpt("host").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("port").hasArg().build();
options.addOption(option);
option = Option.builder("u").hasArg().build();
options.addOption(option);
option = Option.builder("p").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("href").hasArg().build();
options.addOption(option);
option = Option.builder("t").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("file").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("filetype").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("slug").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("onBehalfOf").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("formatNamespace").hasArg().build();
options.addOption(option);
option = Option.builder().longOpt("checksumError").build();
options.addOption(option);
option = Option.builder().longOpt("dest").hasArg().build();
options.addOption(option);
DefaultParser parser = new DefaultParser();
CommandLine command;
try {
command = parser.parse(options, args);
} catch (ParseException ex) {
log.error(ex.getMessage());
return false;
}
if (command.hasOption("help")) {
return false; // force the calling code to display the usage information.
}
md5 = command.hasOption("md5");
noOp = command.hasOption("noOp");
verbose = command.hasOption("verbose");
if (command.hasOption("cmd")) {
guiMode = false;
}
if (command.hasOption("gui")) {
guiMode = true;
}
proxyHost = command.getOptionValue("host");
if (command.hasOption("port")) {
proxyPort = Integer.parseInt(command.getOptionValue("port"));
}
username = command.getOptionValue("u");
password = command.getOptionValue("p");
href = command.getOptionValue("href");
accessType = command.getOptionValue("t");
filename = command.getOptionValue("file");
filetype = command.getOptionValue("filetype");
slug = command.getOptionValue("slug");
onBehalfOf = command.getOptionValue("onBehalfOf");
formatNamespace = command.getOptionValue("formatNamespace");
checksumError = command.hasOption("checksumError");
noCapture = command.hasOption("nocapture");
if (command.hasOption("dest")) {
String dest = command.getOptionValue("dest");
Matcher m = MULTI_PATTERN.matcher(dest);
if (!m.matches()) {
log.debug("Error with dest parameter. Ignoring value: {}", dest);
} else {
int numGroups = m.groupCount();
for (int g = 0; g <= numGroups; g++) {
log.debug("Group ({}) is: {}", g, m.group(g));
}
String group_username = m.group(1);
String group_onBehalfOf = m.group(3);
String group_password = m.group(5);
String group_url = m.group(6);
PostDestination destination = new PostDestination(group_url,
group_username, group_password, group_onBehalfOf);
multiPost.add(destination);
}
}
try {
// apply any settings
if (href == null && "service".equals(accessType)) {
log.error("No href specified.");
return false;
}
if (multiPost.isEmpty() && "multipost".equals(accessType)) {
log.error("No destinations specified");
return false;
}
if (accessType == null && !guiMode) {
log.error("No access type specified");
return false;
}
if ((username == null && password != null) || (username != null && password == null)) {
log.error(
"The username and/or password are not specified. If one is specified, the other must also be " +
"specified.");
return false;
}
} catch (ArrayIndexOutOfBoundsException ex) {
log.error("Error with parameters.");
return false;
}
return true;
}
/**
* Get the access type.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getAccessType() {
return accessType;
}
/**
* Set the access type.
*
* @param accessType The value, or <code>null</code> to clear the value.
*/
public void setAccessType(String accessType) {
this.accessType = accessType;
}
/**
* Get the proxy host.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getProxyHost() {
return proxyHost;
}
/**
* Set the proxy host.
*
* @param proxyHost The value, or <code>null</code> to clear the value.
*/
public void setProxyHost(String proxyHost) {
this.proxyHost = proxyHost;
}
/**
* Get the proxy port.
*
* @return The proxy port. Default value is 80.
*/
public int getProxyPort() {
return proxyPort;
}
/**
* Set the proxy port.
*
* @param proxyPort The proxy port.
*/
public void setProxyPort(int proxyPort) {
this.proxyPort = proxyPort;
}
/**
* Get the username.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getUsername() {
return username;
}
/**
* Set the username.
*
* @param username The value, or <code>null</code> to clear the value.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Get the password.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getPassword() {
return password;
}
/**
* Set the password.
*
* @param password The value, or <code>null</code> to clear the value.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Get the HREF of the service to access.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getHref() {
return href;
}
/**
* Set the HREF of the service to access.
*
* @param href The value, or <code>null</code> to clear the value.
*/
public void setHref(String href) {
this.href = href;
}
/**
* Get the name of the file to post.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getFilename() {
return filename;
}
/**
* Set the name of the file to post.
*
* @param filename The value, or <code>null</code> to clear the value.
*/
public void setFilename(String filename) {
this.filename = filename;
}
/**
* Get the type of the file to post.
*
* @return The filetype, or <code>null</code> if the value is not set.
*/
public String getFiletype() {
return filetype;
}
/**
* Set the type of the file to post.
*
* @param filetype The value, or <code>null</code> to clear the value.
*/
public void setFiletype(String filetype) {
this.filetype = filetype;
}
/**
* Determine if the tool is to be run in GUI mode.
*
* @return True if the tool is set for GUI mode.
*/
public boolean isGuiMode() {
return guiMode;
}
/**
* Set the tool to run in GUI mode.
*
* @param guiMode True if the tool is to run in gui mode.
*/
public void setGuiMode(boolean guiMode) {
this.guiMode = guiMode;
}
/**
* Get the MD5 setting. True if the tool is to use MD5 for post operations.
*
* @return The MD5 setting.
*/
public boolean isMd5() {
return md5;
}
/**
* Set the MD5 setting.
*
* @param md5 True if the tool should use MD5 for post operations.
*/
public void setMd5(boolean md5) {
this.md5 = md5;
}
/**
* Determine if the NoOp header should be sent.
*
* @return True if the header should be sent.
*/
public boolean isNoOp() {
return noOp;
}
/**
* Set the NoOp setting.
*
* @param noOp True if the NoOp header should be used.
*/
public void setNoOp(boolean noOp) {
this.noOp = noOp;
}
/**
* Determine if the verbose option is set.
*
* @return True if verbose option is set.
*/
public boolean isVerbose() {
return verbose;
}
/**
* Set the verbose option.
*
* @param verbose True if verbose should be set.
*/
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
/**
* Get the onBehalfOf value.
*
* @return The value, or <code>null</code> to clear the value.
*/
public String getOnBehalfOf() {
return onBehalfOf;
}
/**
* Set the onBehalf of Value.
*
* @param onBehalfOf The value, or <code>null</code> to clear the value.
*/
public void setOnBehalfOf(String onBehalfOf) {
this.onBehalfOf = onBehalfOf;
}
/**
* Get the format namespace value.
*
* @return The value, or <code>null</code> if the value is not set.
*/
public String getFormatNamespace() {
return formatNamespace;
}
/**
* Set the format namespace value.
*
* @param formatNamespace The value, or <code>null</code> to clear the value.
*/
public void setFormatNamespace(String formatNamespace) {
this.formatNamespace = formatNamespace;
}
/**
* Get the checksum error value.
*
* @return True if an error should be introduced into the checksum.
*/
public boolean getChecksumError() {
return checksumError;
}
/**
* Set the checksum error value.
*
* @param checksumError True if the error should be introduced.
*/
public void setChecksumError(boolean checksumError) {
this.checksumError = checksumError;
}
/**
* Get the current slug header.
*
* @return The slug value, or <code>null</code> if the value is not set.
*/
public String getSlug() {
return this.slug;
}
/**
* Set the text that is to be used for the slug header.
*
* @param slug The value, or <code>null</code> to clear the value.
*/
public void setSlug(String slug) {
this.slug = slug;
}
/**
* Get the list of post destinations.
*
* @return An iterator over the list of PostDestination objects.
*/
public Iterator<PostDestination> getMultiPost() {
return multiPost.iterator();
}
/**
* Determine if the noCapture option is set. This indicates that the code
* should not attempt to redirect stdout and stderr to a different output
* destination. Intended for use in a GUI client.
*
* @return The noCapture setting. True if set.
*/
public boolean isNoCapture() {
return noCapture;
}
}

View File

@@ -1,23 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Interface for a client. This contains a single method that allows the factory
* to pass a set of command line options to the client.
*
* @author Neil Taylor
*/
public interface ClientType {
/**
* Run the client, processing the specified options.
*
* @param options The options extracted from the command line.
*/
public void run(ClientOptions options);
}

View File

@@ -1,445 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import org.apache.logging.log4j.Logger;
import org.purl.sword.atom.Author;
import org.purl.sword.atom.Content;
import org.purl.sword.atom.Contributor;
import org.purl.sword.atom.Generator;
import org.purl.sword.atom.Link;
import org.purl.sword.atom.Rights;
import org.purl.sword.atom.Summary;
import org.purl.sword.atom.Title;
import org.purl.sword.base.Collection;
import org.purl.sword.base.DepositResponse;
import org.purl.sword.base.SWORDEntry;
import org.purl.sword.base.ServiceDocument;
import org.purl.sword.base.SwordAcceptPackaging;
import org.purl.sword.base.Workspace;
/**
* Example implementation of a command line client. This can send out service
* document requests and print out the results and process posting a file to
* either a single or multiple destinations. The command line options are
* initialised prior to calling the class. The options are passed into the
* run(ClientOptions) method.
*
* @author Neil Taylor
*/
public class CmdClient implements ClientType {
/**
* The client that is used to process the service and post requests.
*/
private SWORDClient client;
/**
* List of the options that can be specified on the command line.
*/
private ClientOptions options;
/**
* The logger.
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(CmdClient.class);
/**
* Create a new instance of the class and create an instance of the
* client.
*/
public CmdClient() {
client = new Client();
}
/**
* Process the options that have been initialised from the command line.
* This will call one of service(), post() or multiPost().
*/
public void process() {
if (options.getProxyHost() != null) {
client.setProxy(options.getProxyHost(), options.getProxyPort());
}
try {
String accessType = options.getAccessType();
if (ClientOptions.TYPE_SERVICE.equals(accessType)) {
service();
} else if (ClientOptions.TYPE_POST.equals(accessType)) {
post();
} else if (ClientOptions.TYPE_MULTI_POST.equals(accessType)) {
System.out.println("checking multi-post");
multiPost();
} else {
System.out.println("Access type not recognised.");
}
} catch (MalformedURLException mex) {
System.out
.println("The specified href was not valid: " + options.getHref() + " message: " + mex.getMessage());
} catch (SWORDClientException ex) {
System.out.println("Exception: " + ex.getMessage());
log.error("Unable to process request", ex);
}
}
/**
* Process the service operation. Output the results of the service request.
*
* @throws SWORDClientException if there is an error processing the service request.
* @throws MalformedURLException if there is an error with the URL for the service request.
*/
private void service()
throws SWORDClientException, MalformedURLException {
String href = options.getHref();
initialiseServer(href, options.getUsername(), options.getPassword());
ServiceDocument document = client.getServiceDocument(href, options.getOnBehalfOf());
Status status = client.getStatus();
System.out.println("The status is: " + status);
if (status.getCode() == 200) {
log.debug("message is: " + document.marshall());
System.out.println("\nThe following Details were retrieved: ");
System.out.println("SWORD Version: "
+ document.getService().getVersion());
System.out.println("Supports NoOp? " + document.getService().isNoOp());
System.out.println("Supports Verbose? "
+ document.getService().isVerbose());
System.out.println("Max Upload File Size "
+ document.getService().getMaxUploadSize() + " kB");
Iterator<Workspace> workspaces = document.getService().getWorkspaces();
for (; workspaces.hasNext(); ) {
Workspace workspace = workspaces.next();
System.out.println("\nWorkspace Title: '"
+ workspace.getTitle() + "'");
System.out.println("\n+ Collections ---");
// process the collections
Iterator<Collection> collections = workspace
.collectionIterator();
for (; collections.hasNext(); ) {
Collection collection = collections.next();
System.out.println("\nCollection location: "
+ collection.getLocation());
System.out.println("Collection title: "
+ collection.getTitle());
System.out
.println("Abstract: " + collection.getAbstract());
System.out.println("Collection Policy: "
+ collection.getCollectionPolicy());
System.out.println("Treatment: "
+ collection.getTreatment());
System.out.println("Mediation: "
+ collection.getMediation());
String[] accepts = collection.getAccepts();
if (accepts != null && accepts.length == 0) {
System.out.println("Accepts: none specified");
} else {
for (String s : accepts) {
System.out.println("Accepts: " + s);
}
}
List<SwordAcceptPackaging> acceptsPackaging = collection.getAcceptPackaging();
StringBuilder acceptPackagingList = new StringBuilder();
for (Iterator i = acceptsPackaging.iterator(); i.hasNext(); ) {
SwordAcceptPackaging accept = (SwordAcceptPackaging) i.next();
acceptPackagingList.append(accept.getContent()).append(" (").append(accept.getQualityValue())
.append("), ");
}
System.out.println("Accepts Packaging: " + acceptPackagingList.toString());
}
System.out.println("+ End of Collections ---");
}
}
}
/**
* Perform a post. If any of the destination URL, the filename and the
* filetype are missing, the user will be prompted to enter the values.
*
* @throws SWORDClientException if there is an error processing the post for a requested
* destination.
* @throws MalformedURLException if there is an error with the URL for the post.
*/
private void post()
throws SWORDClientException, MalformedURLException {
String url = options.getHref();
if (url == null) {
url = readLine("Please enter the URL for the deposit: ");
}
initialiseServer(url, options.getUsername(), options.getPassword());
String file = options.getFilename();
if (file == null) {
file = readLine("Please enter the filename to deposit: ");
}
String type = options.getFiletype();
if (type == null) {
type = readLine("Please enter the file type, e.g. application/zip: ");
}
PostMessage message = new PostMessage();
message.setFilepath(file);
message.setDestination(url);
message.setFiletype(type);
message.setUseMD5(options.isMd5());
message.setVerbose(options.isVerbose());
message.setNoOp(options.isNoOp());
message.setFormatNamespace(options.getFormatNamespace());
message.setOnBehalfOf(options.getOnBehalfOf());
message.setChecksumError(options.getChecksumError());
message.setUserAgent(ClientConstants.SERVICE_NAME);
processPost(message);
}
/**
* Perform a multi-post. Iterate over the list of -dest arguments in the command line
* options. For each -dest argument, attempt to post the file to the server.
*
* @throws SWORDClientException if there is an error processing the post for a requested
* destination.
* @throws MalformedURLException if there is an error with the URL for the post.
*/
private void multiPost()
throws SWORDClientException, MalformedURLException {
// request the common information
String file = options.getFilename();
if (file == null) {
file = readLine("Please enter the filename to deposit: ");
}
String type = options.getFiletype();
if (type == null) {
type = readLine("Please enter the file type, e.g. application/zip: ");
}
// process this information for each of the specified destinations
PostDestination destination;
String url = null;
Iterator<PostDestination> iterator = options.getMultiPost();
while (iterator.hasNext()) {
destination = iterator.next();
url = destination.getUrl();
initialiseServer(url, destination.getUsername(), destination.getPassword());
String onBehalfOf = destination.getOnBehalfOf();
if (onBehalfOf == null) {
onBehalfOf = "";
} else {
onBehalfOf = " on behalf of: " + onBehalfOf;
}
System.out.println("Sending file to: " + url + " for: " + destination.getUsername() +
onBehalfOf);
PostMessage message = new PostMessage();
message.setFilepath(file);
message.setDestination(url);
message.setFiletype(type);
message.setUseMD5(options.isMd5());
message.setVerbose(options.isVerbose());
message.setNoOp(options.isNoOp());
message.setFormatNamespace(options.getFormatNamespace());
message.setOnBehalfOf(destination.getOnBehalfOf());
message.setChecksumError(options.getChecksumError());
message.setUserAgent(ClientConstants.SERVICE_NAME);
processPost(message);
}
}
/**
* Process the post response. The message contains the list of arguments
* for the post. The method will then print out the details of the
* response.
*
* @param message The post options.
* @throws SWORDClientException if there is an error accessing the
* post response.
*/
protected void processPost(PostMessage message)
throws SWORDClientException {
DepositResponse response = client.postFile(message);
System.out.println("The status is: " + client.getStatus());
if (response != null) {
log.debug("message is: " + response.marshall());
// iterate over the data and output it
SWORDEntry entry = response.getEntry();
System.out.println("Id: " + entry.getId());
Title title = entry.getTitle();
if (title != null) {
System.out.print("Title: " + title.getContent() + " type: ");
if (title.getType() != null) {
System.out.println(title.getType().toString());
} else {
System.out.println("Not specified.");
}
}
// process the authors
Iterator<Author> authors = entry.getAuthors();
while (authors.hasNext()) {
Author author = authors.next();
System.out.println("Author - " + author.toString());
}
Iterator<String> categories = entry.getCategories();
while (categories.hasNext()) {
System.out.println("Category: " + categories.next());
}
Iterator<Contributor> contributors = entry.getContributors();
while (contributors.hasNext()) {
Contributor contributor = contributors.next();
System.out.println("Contributor - " + contributor.toString());
}
Iterator<Link> links = entry.getLinks();
while (links.hasNext()) {
Link link = links.next();
System.out.println(link.toString());
}
Generator generator = entry.getGenerator();
if (generator != null) {
System.out.println("Generator - " + generator.toString());
} else {
System.out.println("There is no generator");
}
System.out.println("Published: " + entry.getPublished());
Content content = entry.getContent();
if (content != null) {
System.out.println(content.toString());
} else {
System.out.println("There is no content element.");
}
Rights right = entry.getRights();
if (right != null) {
System.out.println(right.toString());
} else {
System.out.println("There is no right element.");
}
Summary summary = entry.getSummary();
if (summary != null) {
System.out.println(summary.toString());
} else {
System.out.println("There is no summary element.");
}
System.out.println("Update: " + entry.getUpdated());
System.out.println("Published: " + entry.getPublished());
System.out.println("Verbose Description: " + entry.getVerboseDescription());
System.out.println("Treatment: " + entry.getTreatment());
System.out.println("Packaging: " + entry.getPackaging());
if (entry.isNoOpSet()) {
System.out.println("NoOp: " + entry.isNoOp());
}
} else {
System.out.println("No valid Entry document was received from the server");
}
}
/**
* Initialise the server. Set the server that will be connected to and
* initialise any username and password. If the username and password are
* either null or contain empty strings, the user credentials will be cleared.
*
* @param location The location to connect to. This is a URL, of the format,
* http://a.host.com:port/. The host name and port number will
* be extracted. If the port is not specified, a default port of
* 80 will be used.
* @param username The username. If this is null or an empty string, the basic
* credentials will be cleared.
* @param password The password. If this is null or an empty string, the basic
* credentials will be cleared.
* @throws MalformedURLException if there is an error processing the URL.
*/
private void initialiseServer(String location, String username, String password)
throws MalformedURLException {
URL url = new URL(location);
int port = url.getPort();
if (port == -1) {
port = 80;
}
client.setServer(url.getHost(), port);
if (username != null && username.length() > 0 &&
password != null && password.length() > 0) {
log.info("Setting the username/password: " + username + " "
+ password);
client.setCredentials(username, password);
} else {
client.clearCredentials();
}
}
/**
* Read a line of text from System.in. If there is an error reading
* from the input, the prompt will be redisplayed and the user asked
* to try again.
*
* @param prompt The prompt to display before the prompt.
* @return The string that is read from the line.
*/
private String readLine(String prompt) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String result = null;
boolean ok = false;
while (!ok) {
try {
System.out.print(prompt);
System.out.flush();
result = reader.readLine();
ok = true;
} catch (IOException ex) {
System.out.println("There was an error with your input. Please try again.");
}
}
return result;
}
/**
* Run the client and process the specified options.
*
* @param options The command line options.
*/
public void run(ClientOptions options) {
this.options = options;
process();
}
}

View File

@@ -1,44 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import java.io.IOException;
import java.io.OutputStream;
/**
* A stream that will write any output to the specified panel.
*
* @author Neil Taylor
*/
public class DebugOutputStream extends OutputStream {
/**
* Panel that will display the messages.
*/
private MessageOutputPanel panel;
/**
* Create a new instance and specify the panel that will receive the output.
*
* @param panel The panel.
*/
public DebugOutputStream(MessageOutputPanel panel) {
this.panel = panel;
}
/**
* Override the write method from OutputStream. Capture the char and
* send it to the panel.
*
* @param arg0 The output character, expressed as an integer.
* @see java.io.OutputStream#write(int)
*/
public void write(int arg0) throws IOException {
panel.addCharacter(Character.valueOf((char) arg0));
}
}

View File

@@ -1,138 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Copyright (c) 2007, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the Centre for Advanced Software and
* Intelligent Systems (CASIS) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.purl.sword.client;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* Panel to display output messages. Text or characters can be sent to the
* panel for display. The panel also includes a button to clear any
* text that is currently displayed.
*
* @author Neil Taylor
*/
public class MessageOutputPanel extends JPanel
implements ActionListener {
/**
* The text area that displays the messages.
*/
private JTextArea messages = null;
/**
* Create a new instance and initialise the panel.
*/
public MessageOutputPanel() {
super();
setLayout(new GridBagLayout());
messages = new JTextArea();
JScrollPane detailsPane = new JScrollPane(messages,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(this);
//add components and set constraints
//dpc = details pane constraint
GridBagConstraints dpc = new GridBagConstraints();
dpc.gridx = 0;
dpc.gridy = 0;
dpc.fill = GridBagConstraints.BOTH;
dpc.weightx = 0.75;
dpc.weighty = 0.45;
dpc.gridwidth = 2;
dpc.insets = new Insets(5, 5, 5, 5);
add(detailsPane, dpc);
//cbc = clear button constraint
GridBagConstraints cbc = new GridBagConstraints();
cbc.gridx = 1;
cbc.gridy = 1;
cbc.insets = new Insets(0, 0, 5, 5);
cbc.anchor = GridBagConstraints.LINE_END;
add(clearButton, cbc);
}
/**
* Add a message to the text area. The message will be added with a carriage return.
*
* @param message The message.
*/
public void addMessage(String message) {
messages.insert(message + "\n", messages.getDocument().getLength());
}
/**
* Add a single character to the text area.
*
* @param character The character.
*/
public void addCharacter(Character character) {
messages.insert(character.toString(), messages.getDocument().getLength());
}
/**
* Clear the text from the display.
*
* @param arg0 The action event.
*
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent arg0) {
messages.setText("");
}
}

View File

@@ -1,140 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Details for a destination. This is used to represent a destination. If
* expressed as a string, the destination looks like:
* <pre>
* &lt;user&gt;[&lt;onBehalfOf&gt;]:&lt;password&gt;@&lt;url&gt;
* </pre>
*
* @author Neil Taylor
*/
public class PostDestination {
/**
* URL for the post destination.
*/
private String url;
/**
* The username.
*/
private String username;
/**
* The password.
*/
private String password;
/**
* The onBehalfOf ID.
*/
private String onBehalfOf;
/**
* Create a new instance.
*/
public PostDestination() {
// No-Op
}
/**
* Create a new instance.
*
* @param url The url.
* @param username The username.
* @param password The password.
* @param onBehalfOf The onBehalfOf id.
*/
public PostDestination(String url, String username, String password, String onBehalfOf) {
this.url = url;
this.username = username;
this.password = password;
this.onBehalfOf = onBehalfOf;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @param url the url to set
*/
public void setUrl(String url) {
this.url = url;
}
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the onBehalfOf
*/
public String getOnBehalfOf() {
return onBehalfOf;
}
/**
* @param onBehalfOf the onBehalfOf to set
*/
public void setOnBehalfOf(String onBehalfOf) {
this.onBehalfOf = onBehalfOf;
}
/**
* Create a string representation of this object.
*
* @return The string.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(username);
if (onBehalfOf != null) {
buffer.append("[");
buffer.append(onBehalfOf);
buffer.append("]");
}
if (password != null) {
buffer.append(":******");
}
buffer.append("@");
buffer.append(url);
return buffer.toString();
}
}

View File

@@ -1,599 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Copyright (c) 2007, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the Centre for Advanced Software and
* Intelligent Systems (CASIS) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.purl.sword.client;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Dialog for users to enter details of post destinations.
*
* @author Neil Taylor
*/
public class PostDialog
implements ActionListener, ChangeListener {
/**
* label for the browse command.
*/
protected static final String BROWSE = "browse";
/**
* label for the add command.
*/
protected static final String ADD = "add";
/**
* label for the edit command.
*/
protected static final String EDIT = "edit";
/**
* label for the delete command.
*/
protected static final String DELETE = "delete";
/**
* label for the clear command.
*/
protected static final String CLEAR = "clear";
/**
* Username combo box.
*/
private SWORDComboBox username;
/**
* Post Location combo box.
*/
private SWORDComboBox postLocation;
/**
* Password field.
*/
private JPasswordField password;
/**
* The file combo box.
*/
private SWORDComboBox file;
/**
* The filetype combo box.
*/
private SWORDComboBox fileType;
/**
* The onBehalfOf combo box.
*/
private SWORDComboBox onBehalfOf;
/**
* The md5 checkbox.
*/
private JCheckBox useMD5;
/**
* The corruptMD5 checkbox.
*/
private JCheckBox corruptMD5;
/**
* The corruptRequest checkbox.
*/
private JCheckBox corruptRequest;
/**
* The useNoOp checkbox.
*/
private JCheckBox useNoOp;
/**
* The verbose checkbox.
*/
private JCheckBox useVerbose;
/**
* The format namespace combo box.
*/
private SWORDComboBox formatNamespace;
/**
* The list of post destinations.
*/
private JList list;
/**
* The parent frame for the dialog that is displayed.
*/
private JFrame parentFrame = null;
/**
* Array that lists the labels for the buttons on the panel.
*/
private static Object[] options = {"Post File", "Cancel"};
/**
* The panel that holds the controls to show.
*/
private JPanel controls = null;
/**
*
* @param parentFrame the parent of this dialog.
*/
public PostDialog(JFrame parentFrame) {
this.parentFrame = parentFrame;
controls = createControls();
}
/**
* Show the dialog with ok and cancel options.
* @return The return value from displaying JOptionPane. Either
* JOptionPane.OK_OPTION or JOptionPane.CANCEL_OPTION.
*/
public int show() {
int result = JOptionPane.showOptionDialog(parentFrame,
controls,
"Post Document",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE,
null,
options,
null);
if (result == JOptionPane.OK_OPTION) {
// update the combo boxes with the values
username.updateList();
file.updateList();
fileType.updateList();
onBehalfOf.updateList();
formatNamespace.updateList();
}
return result;
}
/**
* Create the controls for the main panel.
*
* @return The panel.
*/
protected final JPanel createControls() {
file = new SWORDComboBox();
JPanel filePanel = new JPanel(new BorderLayout());
filePanel.add(file, BorderLayout.CENTER);
JButton browse = new JButton("Browse...");
browse.setActionCommand(BROWSE);
browse.addActionListener(this);
filePanel.add(browse, BorderLayout.SOUTH);
fileType = new SWORDComboBox();
String type = "application/zip";
fileType.addItem(type);
fileType.setSelectedItem(type);
// controls that will be used in the second dialog
postLocation = new SWORDComboBox();
username = new SWORDComboBox();
password = new JPasswordField();
onBehalfOf = new SWORDComboBox();
useMD5 = new JCheckBox();
useMD5.addChangeListener(this);
corruptMD5 = new JCheckBox();
corruptRequest = new JCheckBox();
useNoOp = new JCheckBox();
useVerbose = new JCheckBox();
formatNamespace = new SWORDComboBox();
JLabel fileLabel = new JLabel("File:", JLabel.TRAILING);
JLabel fileTypeLabel = new JLabel("File Type:", JLabel.TRAILING);
JLabel useMD5Label = new JLabel("Use MD5:", JLabel.TRAILING);
JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING);
JLabel corruptRequestLabel = new JLabel("Corrupt Request:", JLabel.TRAILING);
//JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING);
JLabel useNoOpLabel = new JLabel("Use noOp:", JLabel.TRAILING);
JLabel useVerboseLabel = new JLabel("Use verbose:", JLabel.TRAILING);
JLabel formatNamespaceLabel = new JLabel("X-Packaging:", JLabel.TRAILING);
JLabel userAgentLabel = new JLabel("User Agent:", JLabel.TRAILING);
JLabel userAgentNameLabel = new JLabel(ClientConstants.SERVICE_NAME, JLabel.LEADING);
SWORDFormPanel panel = new SWORDFormPanel();
panel.addFirstRow(new JLabel("Please enter the details for the post operation"));
JPanel destinations = createDestinationsPanel();
panel.addRow(new JLabel("Destinations:"), destinations);
panel.addRow(fileLabel, filePanel);
panel.addRow(fileTypeLabel, fileType);
panel.addRow(useMD5Label, useMD5);
panel.addRow(corruptMD5Label, corruptMD5);
panel.addRow(corruptRequestLabel, corruptRequest);
panel.addRow(useNoOpLabel, useNoOp);
panel.addRow(useVerboseLabel, useVerbose);
panel.addRow(formatNamespaceLabel, formatNamespace);
panel.addRow(userAgentLabel, userAgentNameLabel);
return panel;
}
/**
* Create the destinations panel. This contains a list and four buttons
* to operate on values in the list.
*
* @return The panel containing the controls.
*/
protected JPanel createDestinationsPanel() {
DefaultListModel model = new DefaultListModel();
list = new JList(model);
JScrollPane jsp = new JScrollPane(list);
JPanel destinations = new JPanel(new BorderLayout());
destinations.add(jsp, BorderLayout.CENTER);
JPanel destinationButtons = new JPanel();
JButton addButton = new JButton("Add");
addButton.setActionCommand(ADD);
addButton.addActionListener(this);
JButton editButton = new JButton("Edit");
editButton.setActionCommand(EDIT);
editButton.addActionListener(this);
JButton deleteButton = new JButton("Delete");
deleteButton.setActionCommand(DELETE);
deleteButton.addActionListener(this);
JButton clearButton = new JButton("Clear");
clearButton.setActionCommand(CLEAR);
clearButton.addActionListener(this);
destinationButtons.add(addButton);
destinationButtons.add(editButton);
destinationButtons.add(deleteButton);
destinationButtons.add(clearButton);
destinations.add(destinationButtons, BorderLayout.SOUTH);
return destinations;
}
/**
* Handle the button click to select a file to upload.
*/
public void actionPerformed(ActionEvent evt) {
String cmd = evt.getActionCommand();
if (BROWSE.equals(cmd)) {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
int returnVal = chooser.showOpenDialog(parentFrame);
if (returnVal == JFileChooser.APPROVE_OPTION) {
file.setSelectedItem(chooser.getSelectedFile().getAbsolutePath());
}
} else if (ADD.equals(cmd)) {
PostDestination dest = showDestinationDialog(null);
if (dest != null) {
((DefaultListModel) list.getModel()).addElement(dest);
}
} else if (EDIT.equals(cmd)) {
PostDestination dest = (PostDestination) list.getSelectedValue();
if (dest != null) {
showDestinationDialog(dest);
list.repaint();
}
} else if (DELETE.equals(cmd)) {
if (list.getSelectedIndex() != -1) {
((DefaultListModel) list.getModel()).removeElementAt(list.getSelectedIndex());
}
} else if (CLEAR.equals(cmd)) {
((DefaultListModel) list.getModel()).clear();
}
}
/**
* Show the destination dialog. This is used to enter the URL,
* username, password and onBehalfOf name for a destination.
*
* @param destination The post destination. If this is not null, the values
* in the object are used to set the current values
* in the dialog controls.
* @return The post destination value.
*/
public PostDestination showDestinationDialog(PostDestination destination) {
SWORDFormPanel panel = new SWORDFormPanel();
panel.addFirstRow(new JLabel("Please enter the details for the post operation"));
JLabel postLabel = new JLabel("Post Location:", JLabel.TRAILING);
JLabel userLabel = new JLabel("Username:", JLabel.TRAILING);
JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING);
JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING);
panel.addRow(postLabel, postLocation);
panel.addRow(userLabel, username);
panel.addRow(passwordLabel, password);
panel.addRow(onBehalfOfLabel, onBehalfOf);
if (destination != null) {
postLocation.insertItem(destination.getUrl());
username.insertItem(destination.getUsername());
password.setText(destination.getPassword());
onBehalfOf.insertItem(destination.getOnBehalfOf());
} else {
String s = "";
postLocation.insertItem(s);
//postLocation.setSelectedItem(s);
username.insertItem(s);
username.setSelectedItem(s);
password.setText(s);
onBehalfOf.insertItem(s);
onBehalfOf.setSelectedItem(s);
}
int result = JOptionPane.showOptionDialog(null,
panel,
"Destination",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE,
null,
new String[] {"OK", "Cancel"},
null);
if (result == JOptionPane.OK_OPTION) {
postLocation.updateList();
username.updateList();
onBehalfOf.updateList();
if (destination == null) {
destination = new PostDestination();
}
destination.setUrl(postLocation.getText());
destination.setUsername(username.getText());
String pass = new String(password.getPassword());
if (pass.length() > 0) {
destination.setPassword(pass);
} else {
destination.setPassword(null);
}
String obo = onBehalfOf.getText();
if (obo.length() > 0) {
destination.setOnBehalfOf(onBehalfOf.getText());
} else {
destination.setOnBehalfOf(null);
}
}
return destination;
}
/**
* Get the list of Post Destinations.
* @return The destinations.
*/
public PostDestination[] getDestinations() {
DefaultListModel model = (DefaultListModel) list.getModel();
PostDestination[] destinations = new PostDestination[model.size()];
for (int i = 0; i < model.size(); i++) {
destinations[i] = (PostDestination) model.get(i);
}
return destinations;
}
/**
* Get the file details.
* @return The value.
*/
public String getFile() {
return file.getText();
}
/**
* Get the filetype value.
* @return The value.
*/
public String getFileType() {
return fileType.getText();
}
/**
* Get the onBehalfOf value.
* @return The value.
*/
public String getOnBehalfOf() {
return onBehalfOf.getText();
}
/**
* Get the format namespace value.
* @return The value.
*/
public String getFormatNamespace() {
return formatNamespace.getText();
}
/**
* Determine if the MD5 checkbox is selected.
*
* @return True if the MD5 checkbox is selected.
*/
public boolean useMd5() {
return useMD5.isSelected();
}
/**
* Determine if the noOp checkbox is selected.
*
* @return True if the checkbox is selected.
*/
public boolean useNoOp() {
return useNoOp.isSelected();
}
/**
* Determine if the verbose checkbox is selected.
*
* @return True if the checkbox is selected.
*/
public boolean useVerbose() {
return useVerbose.isSelected();
}
/**
* Get the post location.
* @return The post location.
*/
public String getPostLocation() {
return postLocation.getText();
}
/**
* Determine if the MD5 hash should be corrupted.
* @return True if the corrupt MD5 checkbox is selected. The MD5 checkbox
* must also be selected.
*/
public boolean corruptMD5() {
return (corruptMD5.isEnabled() && corruptMD5.isSelected());
}
/**
* Determine if the POST request should be corrupted.
* @return True if the corrupt request checkbox is selected.
*/
public boolean corruptRequest() {
return (corruptRequest.isSelected());
}
/**
* Detect a state change event for the checkbox.
*
* @param evt The event.
*/
public void stateChanged(ChangeEvent evt) {
corruptMD5.setEnabled(useMD5.isSelected());
}
/**
* Add a list of user ids.
*
* @param users The user ids.
*/
public void addUserIds(String[] users) {
username.insertItems(users);
}
/**
* Add a list of deposit URLs.
*
* @param deposits The URLs.
*/
public void addDepositUrls(String[] deposits) {
postLocation.insertItems(deposits);
}
/**
* Add a list of onBehalfOf names.
*
* @param users The names.
*/
public void addOnBehalfOf(String[] users) {
onBehalfOf.insertItems(users);
}
/**
* Add the list of formatNamespace strings.
*
* @param namespaces list of strings.
*/
public void addFormatNamespaces(String[] namespaces) {
formatNamespace.insertItems(namespaces);
}
/**
* Add a list of file types.
*
* @param types The file types.
*/
public void addFileTypes(String[] types) {
fileType.insertItems(types);
}
/**
* Add a list of file names.
* @param files The list of files.
*/
public void addFiles(String[] files) {
file.insertItems(files);
}
/**
* Set the deposit location.
*
* @param location The location.
*/
public void setDepositLocation(String location) {
postLocation.insertItem(location);
postLocation.setSelectedItem(location);
}
}

View File

@@ -1,344 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Copyright (c) 2007, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the Centre for Advanced Software and
* Intelligent Systems (CASIS) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.purl.sword.client;
import java.io.File;
/**
* Represents the details of a post to a server. The message holds all of the possible values
* that are to be sent from the client to the server. Not all elements of the message
* must be filled in. Any required fields are defined in the current SWORD specification.
*
* @author Neil Taylor
*/
public class PostMessage {
/**
* The local filepath for the file to upload/deposit.
*/
private String filepath;
/**
* The URL of the destination server.
*/
private String destination;
/**
* The filetype of the package that is to be uploaded.
*/
private String filetype;
/**
* The string with the username if the deposit is on behalf of another user.
*/
private String onBehalfOf;
/**
* True if an MD5 checksum should be sent with the deposit.
*/
private boolean useMD5;
/**
* True if the deposit is a test and should not result in an actual deposit.
*/
private boolean noOp;
/**
* True if the verbose operation is requested.
*/
private boolean verbose;
/**
* The packaging format for the deposit.
*/
private String packaging;
/**
* True if the deposit should simulate a checksum error. The client should check this
* field to determine if a correct MD5 checksum should be sent or whether the checksum should
* be modified so that it generates an error at the server.
*/
private boolean checksumError;
/**
* True if the deposit should corrupt the POST header. The client should check this
* field to determine if a correct header should be sent or whether the header should
* be modified so that it generates an error at the server.
*/
private boolean corruptRequest;
/**
* The Slug header value.
*/
private String slug;
/**
* The user agent name
*/
private String userAgent;
/**
* Get the filepath.
*
* @return The filepath.
*/
public String getFilepath() {
return filepath;
}
/**
* Get the filename. This is the last element of the filepath
* that has been set in this class.
*
* @return filename
*/
public String getFilename() {
File file = new File(filepath);
return file.getName();
}
/**
* Set the filepath.
*
* @param filepath The filepath.
*/
public void setFilepath(String filepath) {
this.filepath = filepath;
}
/**
* Get the destination collection.
*
* @return The collection.
*/
public String getDestination() {
return destination;
}
/**
* Set the destination collection.
*
* @param destination The destination.
*/
public void setDestination(String destination) {
this.destination = destination;
}
/**
* Get the filetype.
* @return The filetype.
*/
public String getFiletype() {
return filetype;
}
/**
* Set the filetype.
*
* @param filetype The filetype.
*/
public void setFiletype(String filetype) {
this.filetype = filetype;
}
/**
* Get the onBehalfOf value.
*
* @return The value.
*/
public String getOnBehalfOf() {
return onBehalfOf;
}
/**
* Set the onBehalfOf value.
*
* @param onBehalfOf The value.
*/
public void setOnBehalfOf(String onBehalfOf) {
this.onBehalfOf = onBehalfOf;
}
/**
* Get the MD5 status.
* @return The value.
*/
public boolean isUseMD5() {
return useMD5;
}
/**
* Set the md5 state.
*
* @param useMD5 True if the message should use an MD5 checksum.
*/
public void setUseMD5(boolean useMD5) {
this.useMD5 = useMD5;
}
/**
* Get the no-op state.
*
* @return The value.
*/
public boolean isNoOp() {
return noOp;
}
/**
* Set the no-op state.
*
* @param noOp The no-op.
*/
public void setNoOp(boolean noOp) {
this.noOp = noOp;
}
/**
* Get the verbose value.
*
* @return The value.
*/
public boolean isVerbose() {
return verbose;
}
/**
* Set the verbose state.
*
* @param verbose True if the post message should send a
* verbose header.
*/
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
/**
* Get the packaging format.
*
* @return The value.
*/
public String getPackaging() {
return packaging;
}
/**
* Set the packaging format.
*
* @param packaging The packaging format.
*/
public void setFormatNamespace(String packaging) {
this.packaging = packaging;
}
/**
* Get the status of the checksum error.
*
* @return True if the client should simulate a checksum error.
*/
public boolean getChecksumError() {
return checksumError;
}
/**
* Set the state of the checksum error.
*
* @param checksumError True if the item should include a checksum error.
*/
public void setChecksumError(boolean checksumError) {
this.checksumError = checksumError;
}
/**
* Get the status of the corrupt request flag.
*
* @return True if the client should corrupt the POST header.
*/
public boolean getCorruptRequest() {
return corruptRequest;
}
/**
* Set the state of the corrupt request flag.
*
* @param corruptRequest True if the item should corrupt the POST header.
*/
public void setCorruptRequest(boolean corruptRequest) {
this.corruptRequest = corruptRequest;
}
/**
* Set the Slug value.
*
* @param slug The value.
*/
public void setSlug(String slug) {
this.slug = slug;
}
/**
* Get the Slug value.
*
* @return The Slug.
*/
public String getSlug() {
return this.slug;
}
/**
* @return the userAgent
*/
public String getUserAgent() {
return userAgent;
}
/**
* Set the user agent
*
* @param userAgent the userAgent to set
*/
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
}
}

View File

@@ -1,240 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import java.awt.BorderLayout;
import java.util.Enumeration;
import java.util.Properties;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
/**
* Dialog that is used to edit the collection of properties.
*
* @author Neil Taylor, Suzana Barreto
*/
public class PropertiesDialog {
/**
* The parent frame for the dialog that is displayed.
*/
private JFrame parentFrame = null;
/**
* Array that lists the labels for the buttons on the panel.
*/
private static Object[] options = {"OK", "Cancel"};
/**
* The panel that holds the controls to show.
*/
private JPanel controls = null;
/**
* The configuration properties
*/
private Properties properties = null;
/**
* Table that is used to display the list of properties.
*/
private JTable propertiesTable;
/**
* Create a new instance.
*
* @param parentFrame The parent frame for the dialog.
* @param props The properties lisst to display
*/
public PropertiesDialog(JFrame parentFrame, Properties props) {
this.parentFrame = parentFrame;
properties = props;
controls = createControls();
}
/**
* Create the controls that are to be displayed in the system.
*
* @return A panel that contains the controls.
*/
protected final JPanel createControls() {
JPanel panel = new JPanel(new BorderLayout());
propertiesTable = new JTable(new PropertiesModel());
((DefaultCellEditor) propertiesTable.getDefaultEditor(String.class)).setClickCountToStart(1);
JScrollPane scrollpane = new JScrollPane(propertiesTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
panel.add(scrollpane, BorderLayout.CENTER);
return panel;
}
/**
* Show the dialog and return the status code.
*
* @return The status code returned from the dialog.
*/
public int show() {
int result = JOptionPane.showOptionDialog(parentFrame,
controls,
"Edit Properties",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE,
null,
options,
null);
// cancel any edit in the table. If there is a cell editing, the getEditingColumn will
// return a non-negative column number. This can be used to retreive the cell editor.
// The code then gets the default editor and calls the stopCellEditing. If custom
// editors are used, an additional check must be made to get the cell editor
// for a specific cell.
int column = propertiesTable.getEditingColumn();
if (column > -1) {
TableCellEditor editor = propertiesTable.getDefaultEditor(propertiesTable.getColumnClass(column));
if (editor != null) {
editor.stopCellEditing();
}
}
return result;
}
/**
* A table model that is used to show the properties. The model links directly
* to the underlying properties object. As changes are made in the table, the
* corresponding changes are made in the properties object. The user can only
* edit the value column in the table.
*/
public class PropertiesModel extends AbstractTableModel {
/**
* Column names.
*/
private String columns[] = {"Property Name", "Value"};
/**
* Create a new instance of the model. If no properties object exists,
* a default model is created. Note, this will allow the table to
* continue editing, although this value will not be passed back to
* the calling window.
*/
public PropertiesModel() {
super();
if (properties == null) {
properties = new Properties();
}
}
/**
* Get the number of columns.
*
* @return The number of columns.
*/
public int getColumnCount() {
return columns.length;
}
/**
* Get the number of rows.
*
* @return The number of rows.
*/
public int getRowCount() {
return properties.size();
}
/**
* Get the value that is at the specified cell.
*
* @param row The row for the cell.
* @param col The column for the cell.
* @return The data value from the properties.
*/
public Object getValueAt(int row, int col) {
if (col == 0) {
return getKeyValue(row);
} else {
String key = getKeyValue(row);
return properties.get(key);
}
}
/**
* Retrieve the column name for the specified column.
*
* @param col The column number.
* @return The column name.
*/
public String getColumnName(int col) {
return columns[col];
}
/**
* Retrieve the column class.
*
* @param col The column number.
* @return The class for the object found at the column position.
*/
public Class getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
/**
* Determine if the cell can be edited. This model will only
* allow the second column to be edited.
*
* @param row The cell row.
* @param col The cell column.
* @return True if the cell can be edited. Otherwise, false.
*/
public boolean isCellEditable(int row, int col) {
if (col == 1) {
return true;
}
return false;
}
/**
* Set the value for the specified cell.
*
* @param value The value to set.
* @param row The row for the cell.
* @param col The column.
*/
public void setValueAt(Object value, int row, int col) {
String key = getKeyValue(row);
properties.setProperty(key, ((String) value));
fireTableCellUpdated(row, col);
}
/**
* Get the Key value for the specified row.
*
* @param row The row.
* @return A string that shows the key value.
*/
public String getKeyValue(int row) {
int count = 0;
Enumeration<Object> k = properties.keys();
while (k.hasMoreElements()) {
String key = (String) k.nextElement();
if (count == row) {
return key;
}
count++;
}
return null;
}
}
}

View File

@@ -1,85 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import org.purl.sword.base.DepositResponse;
import org.purl.sword.base.ServiceDocument;
/**
* Interface for any SWORD client implementation.
*/
public interface SWORDClient {
/**
* Set the server that is to be contacted on the next access.
*
* @param server The name of the server, e.g. www.aber.ac.uk
* @param port The port number, e.g. 80.
*/
public void setServer(String server, int port);
/**
* Set the user credentials that are to be used for subsequent accesses.
*
* @param username The username.
* @param password The password.
*/
public void setCredentials(String username, String password);
/**
* Clear the credentials settings on the client.
*/
public void clearCredentials();
/**
* Set the proxy that is to be used for subsequent accesses.
*
* @param host The host name, e.g. cache.host.com.
* @param port The port, e.g. 8080.
*/
public void setProxy(String host, int port);
/**
* Get the status result returned from the most recent network test.
*
* @return The status code and message.
*/
public Status getStatus();
/**
* Get a service document, specified in the URL.
*
* @param url The URL to connect to.
* @return A ServiceDocument that contains the Service details that were
* obained from the specified URL.
* @throws SWORDClientException If there is an error accessing the
* URL.
*/
public ServiceDocument getServiceDocument(String url) throws SWORDClientException;
/**
* Get a service document, specified in the URL. The document is accessed on
* behalf of the specified user.
*
* @param url The URL to connect to.
* @param onBehalfOf The username for the onBehalfOf access.
* @return A ServiceDocument that contains the Service details that were
* obtained from the specified URL.
* @throws SWORDClientException If there is an error accessing the URL.
*/
public ServiceDocument getServiceDocument(String url, String onBehalfOf) throws SWORDClientException;
/**
* Post a file to the specified destination URL.
*
* @param message The message that defines the requirements for the operation.
* @return A DespoitResponse if the response is successful. If there was an error,
* <code>null</code> should be returned.
* @throws SWORDClientException If there is an error accessing the URL.
*/
public DepositResponse postFile(PostMessage message) throws SWORDClientException;
}

View File

@@ -1,42 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Represents an exception thrown by the SWORD Client.
*
* @author Neil Taylor
*/
public class SWORDClientException extends Exception {
/**
* Create a new exception, without a message.
*/
public SWORDClientException() {
super();
}
/**
* Create a new exception with the specified message.
*
* @param message The message.
*/
public SWORDClientException(String message) {
super(message);
}
/**
* Create a new exception with the specified message and set
* the exception that generated this error.
*
* @param message The message.
* @param cause The original exception.
*/
public SWORDClientException(String message, Exception cause) {
super(message, cause);
}
}

View File

@@ -1,129 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Copyright (c) 2007, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the Centre for Advanced Software and
* Intelligent Systems (CASIS) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.purl.sword.client;
import javax.swing.JComboBox;
/**
* An extension of the JComboBox class. This adds a method that
* can update the list of items with the item. The update will only
* work on combo boxes that are set to editable.
*
* @author Neil Taylor
*/
public class SWORDComboBox extends JComboBox {
/**
* Create an instance of the SWORD Combo box.
*/
public SWORDComboBox() {
super();
setEditable(true);
}
/**
* Update the list for the Combo box with the currently selected
* item. This will only add an item to the list if: i) the control
* is editable, ii) the selected item is not empty and iii) the
* item is not already in the list.
*/
public void updateList() {
Object s = getSelectedItem();
if (!isEditable() || s == null || ((String) s).trim().length() == 0) {
// don't update with an empty item or if the combo box is not editable.
return;
}
insertItem(s);
}
/**
* Insert an item into the combo box. This will only be added
* if the item is not already present in the combo box.
*
* @param newItem The item to insert.
*/
public void insertItem(Object newItem) {
int count = getItemCount();
boolean found = false;
for (int i = 0; i < count && !found; i++) {
Object item = getItemAt(i);
if (item != null && item.equals(newItem)) {
found = true;
}
}
if (!found) {
addItem(newItem);
}
}
/**
* Insert multiple items into the combo box.
*
* @param items The array of items.
*/
public void insertItems(String[] items) {
for (String item : items) {
insertItem(item);
}
}
/**
* Get the text of the currently selected item in the combo box.
* @return The text. <code>null</code> is returned if no item
* is selected.
*/
public String getText() {
Object o = getSelectedItem();
if (o != null) {
return o.toString().trim();
}
return null;
}
}

View File

@@ -1,144 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JPanel;
/**
* Utility class. Creates a two column form. The left column is used to show
* the label for the row. The right column is used to show the control, e.g.
* text box, combo box or checkbox, for the row.
*
* @author Neil Taylor
*/
public class SWORDFormPanel extends JPanel {
/**
* Constraints used to control the layout on the panel.
*/
private GridBagConstraints labelConstraints;
/**
* Constraints used to control the layout of the input controls on the panel.
*/
private GridBagConstraints controlConstraints;
/**
* Index to the next row.
*/
private int rowIndex = 0;
/**
* Insets for the top row of the label column.
*/
private Insets labelTop = new Insets(10, 10, 0, 0);
/**
* Insets for the top row of the control column.
*/
private Insets controlTop = new Insets(10, 4, 0, 10);
/**
* Insets for a general row in the label column.
*/
private Insets labelGeneral = new Insets(3, 10, 0, 0);
/**
* Insets for a general row in the control column.
*/
private Insets controlGeneral = new Insets(3, 4, 0, 10);
/**
* Create a new instance of the class.
*/
public SWORDFormPanel() {
super();
setLayout(new GridBagLayout());
labelConstraints = new GridBagConstraints();
labelConstraints.fill = GridBagConstraints.NONE;
labelConstraints.anchor = GridBagConstraints.LINE_END;
labelConstraints.weightx = 0.1;
controlConstraints = new GridBagConstraints();
controlConstraints.fill = GridBagConstraints.HORIZONTAL;
controlConstraints.weightx = 0.9;
}
/**
* Add the specified component as the first row. It will occupy two
* columns.
*
* @param one The control to add.
*/
public void addFirstRow(Component one) {
addRow(one, null, labelTop, controlTop);
}
/**
* Add the specified components as the first row in the form.
*
* @param one The label component.
* @param two The control component.
*/
public void addFirstRow(Component one, Component two) {
addRow(one, two, labelTop, controlTop);
}
/**
* Add a component to the general row. This will be added in the label column.
*
* @param one The component.
*/
public void addRow(Component one) {
addRow(one, null);
}
/**
* Add a component to the general row.
*
* @param one The component to add to the label column.
* @param two The component to add to the control column.
*/
public void addRow(Component one, Component two) {
addRow(one, two, labelGeneral, controlGeneral);
}
/**
* Add a row to the table.
*
* @param one The component to display in the label column.
* @param two The component to display in the control column.
* @param labels The insets for the label column.
* @param controls The insets for the controls column.
*/
protected void addRow(Component one, Component two, Insets labels, Insets controls) {
labelConstraints.insets = labels;
labelConstraints.gridx = 0;
labelConstraints.gridy = rowIndex;
if (two == null) {
labelConstraints.gridwidth = 2;
} else {
labelConstraints.gridwidth = 1;
}
add(one, labelConstraints);
if (two != null) {
controlConstraints.insets = controls;
controlConstraints.gridx = 1;
controlConstraints.gridy = rowIndex;
add(two, controlConstraints);
}
rowIndex++;
}
}

View File

@@ -1,227 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Copyright (c) 2007, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the Centre for Advanced Software and
* Intelligent Systems (CASIS) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.purl.sword.client;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
/**
* Dialog that prompts the user to enter the details for a service
* document location.
*
* @author Neil Taylor
*/
public class ServiceDialog {
/**
* The username.
*/
private SWORDComboBox username;
/**
* The password.
*/
private JPasswordField password;
/**
* Holds the URL for the collection.
*/
private SWORDComboBox location;
/**
* The combo box that shows the list of onBehalfOf items.
*/
private SWORDComboBox onBehalfOf;
/**
* Parent frame for the dialog.
*/
private JFrame parentFrame = null;
/**
* The panel that holds the controls.
*/
private JPanel controls = null;
/**
* List of buttons.
*/
private static Object[] options = {"Get Service Document", "Cancel"};
/**
* Create a new instance.
*
* @param parentFrame The parent frame. The dialog will be shown over the
* centre of this frame.
*/
public ServiceDialog(JFrame parentFrame) {
this.parentFrame = parentFrame;
controls = createControls();
}
/**
* Show the dialog.
*
* @return The close option. This is one of the dialog options from
* JOptionPane.
*/
public int show() {
int result = JOptionPane.showOptionDialog(parentFrame,
controls,
"Get Service Document",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE,
null,
options,
options[1]);
if (result == JOptionPane.OK_OPTION) {
// update the combo boxes with the values
username.updateList();
location.updateList();
onBehalfOf.updateList();
}
return result;
}
/**
* Create the controls that are displayed in the dialog.
*
* @return The panel that contains the controls.
*/
protected final JPanel createControls() {
username = new SWORDComboBox();
username.setEditable(true);
password = new JPasswordField();
location = new SWORDComboBox();
location.setEditable(true);
onBehalfOf = new SWORDComboBox();
onBehalfOf.setEditable(true);
JLabel userLabel = new JLabel("Username:", JLabel.TRAILING);
JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING);
JLabel locationLabel = new JLabel("Location:", JLabel.TRAILING);
JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING);
SWORDFormPanel panel = new SWORDFormPanel();
panel.addFirstRow(userLabel, username);
panel.addRow(passwordLabel, password);
panel.addRow(locationLabel, location);
panel.addRow(onBehalfOfLabel, onBehalfOf);
return panel;
}
/**
* Get the username from the controls on the dialog.
*
* @return The username.
*/
public String getUsername() {
return username.getText();
}
/**
* Get the password from the dialog.
*
* @return The password.
*/
public String getPassword() {
return new String(password.getPassword());
}
/**
* The location from the dialog.
*
* @return The location.
*/
public String getLocation() {
return location.getText();
}
/**
* The onBehalfOf value from the dialog.
*
* @return The onBehalfOf value.
*/
public String getOnBehalfOf() {
String text = onBehalfOf.getText().trim();
if (text.length() == 0) {
return null;
}
return text;
}
/**
* Add the list of user ids to the dialog.
*
* @param users The list of user ids.
*/
public void addUserIds(String[] users) {
username.insertItems(users);
}
/**
* Add the list of service URLs.
*
* @param services The service URLs.
*/
public void addServiceUrls(String[] services) {
location.insertItems(services);
}
/**
* Add a list of onBehalfOf names.
*
* @param users The list of onBehalfOf items.
*/
public void addOnBehalfOf(String[] users) {
onBehalfOf.insertItems(users);
}
}

View File

@@ -1,843 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Copyright (c) 2007, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the Centre for Advanced Software and
* Intelligent Systems (CASIS) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.purl.sword.client;
import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.purl.sword.atom.Author;
import org.purl.sword.atom.Content;
import org.purl.sword.atom.Contributor;
import org.purl.sword.atom.Generator;
import org.purl.sword.atom.Link;
import org.purl.sword.atom.TextConstruct;
import org.purl.sword.base.Collection;
import org.purl.sword.base.DepositResponse;
import org.purl.sword.base.SWORDEntry;
import org.purl.sword.base.Service;
import org.purl.sword.base.ServiceDocument;
import org.purl.sword.base.SwordAcceptPackaging;
import org.purl.sword.base.Workspace;
/**
* The main panel for the GUI client. This contains the top-two sub-panels: the
* tree and the text area to show the details of the selected node.
*
* @author Neil Taylor
*/
public class ServicePanel extends JPanel
implements TreeSelectionListener {
/**
* The top level item in the tree that lists services.
*/
DefaultMutableTreeNode top;
/**
* The tree model used to display the items.
*/
DefaultTreeModel treeModel = null;
/**
* Tree that holds the list of services.
*/
private JTree services;
/**
* The panel that shows an HTML table with any details for the selected
* node in the services tree.
*/
private JEditorPane details;
/**
* A registered listener. This listener will be notified when there is a
* different node selected in the service tree.
*/
private ServiceSelectedListener listener;
/**
* Create a new instance of the panel.
*/
public ServicePanel() {
super();
setLayout(new BorderLayout());
top = new DefaultMutableTreeNode("Services & Posted Files");
treeModel = new DefaultTreeModel(top);
services = new JTree(treeModel);
services.setCellRenderer(new ServicePostTreeRenderer());
JScrollPane servicesPane = new JScrollPane(services,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
details = new JEditorPane("text/html",
"<html><body><h1>Details</h1><p>This panel will show the details for the currently " +
"selected item in the tree.</p></body></html>");
JScrollPane detailsPane = new JScrollPane(details,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
servicesPane,
detailsPane);
splitPane.setOneTouchExpandable(true);
splitPane.setResizeWeight(0.5);
splitPane.setDividerLocation(200);
services.addTreeSelectionListener(this);
ToolTipManager.sharedInstance().registerComponent(services);
add(splitPane, BorderLayout.CENTER);
}
/**
* Renderer that displays the icons for the tree nodes.
*
* @author Neil Taylor
*/
static class ServicePostTreeRenderer extends DefaultTreeCellRenderer {
Icon workspaceIcon;
Icon serviceIcon;
Icon collectionIcon;
Icon fileIcon;
/**
* Initialise the renderer. Load the icons.
*/
public ServicePostTreeRenderer() {
ClassLoader loader = this.getClass().getClassLoader();
workspaceIcon = new ImageIcon(loader.getResource("images/WorkspaceNodeImage.gif"));
serviceIcon = new ImageIcon(loader.getResource("images/ServiceNodeImage.gif"));
collectionIcon = new ImageIcon(loader.getResource("images/CollectionNodeImage.gif"));
fileIcon = new ImageIcon(loader.getResource("images/ServiceNodeImage.gif"));
}
/**
* Return the cell renderer. This will be the default tree cell renderer
* with a different icon depending upon the type of data in the node.
*
* @param tree The JTree control.
* @param value The value to display.
* @param sel True if the node is selected.
* @param expanded True if the node is expanded.
* @param leaf True if the node is a leaf.
* @param row The row.
* @param hasFocus True if the node has focus.
*/
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
JComponent comp = (JComponent) super.getTreeCellRendererComponent(
tree, value, sel,
expanded, leaf, row,
hasFocus);
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) value;
Object o = node.getUserObject();
if (o instanceof TreeNodeWrapper) {
TreeNodeWrapper wrapper = (TreeNodeWrapper) o;
comp.setToolTipText(wrapper.toString());
Object data = wrapper.getData();
if (data instanceof Service) {
setIcon(serviceIcon);
} else if (data instanceof Workspace) {
setIcon(workspaceIcon);
} else if (data instanceof Collection) {
setIcon(collectionIcon);
} else if (data instanceof SWORDEntry) {
setIcon(fileIcon);
}
} else {
comp.setToolTipText(null);
}
return comp;
}
}
/**
* Set the service selected listener. This listener will be notified when
* there is a selection change in the tree.
*
* @param listener The listener.
*/
public void setServiceSelectedListener(ServiceSelectedListener listener) {
this.listener = listener;
}
/**
* Process the specified service document. Add the details as a new child of the
* root of the tree.
*
* @param url The url used to access the service document.
* @param doc The service document.
*/
public void processServiceDocument(String url,
ServiceDocument doc) {
TreeNodeWrapper wrapper = null;
Service service = doc.getService();
wrapper = new TreeNodeWrapper(url, service);
DefaultMutableTreeNode serviceNode = new DefaultMutableTreeNode(wrapper);
treeModel.insertNodeInto(serviceNode, top, top.getChildCount());
services.scrollPathToVisible(new TreePath(serviceNode.getPath()));
// process the workspaces
DefaultMutableTreeNode workspaceNode = null;
Iterator<Workspace> workspaces = service.getWorkspaces();
for (; workspaces.hasNext(); ) {
Workspace workspace = workspaces.next();
wrapper = new TreeNodeWrapper(workspace.getTitle(), workspace);
workspaceNode = new DefaultMutableTreeNode(wrapper);
treeModel.insertNodeInto(workspaceNode, serviceNode, serviceNode.getChildCount());
services.scrollPathToVisible(new TreePath(workspaceNode.getPath()));
DefaultMutableTreeNode collectionNode = null;
Iterator<Collection> collections = workspace.collectionIterator();
for (; collections.hasNext(); ) {
Collection collection = collections.next();
wrapper = new TreeNodeWrapper(collection.getTitle(), collection);
collectionNode = new DefaultMutableTreeNode(wrapper);
treeModel.insertNodeInto(collectionNode, workspaceNode, workspaceNode.getChildCount());
services.scrollPathToVisible(new TreePath(collectionNode.getPath()));
}
} // for
}
/**
* Holds the data for a tree node. It specifies the name that will be displayed
* in the node, and stores associated data.
*
* @author Neil Taylor
*/
static class TreeNodeWrapper {
/**
* The node name.
*/
private String name;
/**
* The user data.
*/
private Object userObject;
/**
* Create a new instance.
*
* @param name The name of the node.
* @param data The data in the node.
*/
public TreeNodeWrapper(String name, Object data) {
this.name = name;
this.userObject = data;
}
/**
* Retrieve the data that is stored in this node.
*
* @return The data.
*/
public Object getData() {
return userObject;
}
/**
* Get a string description for this node.
*/
public String toString() {
if (name == null || name.trim().equals("")) {
return "Unspecified";
}
return name;
}
}
/**
* Respond to a changed tree selection event. Update the details panel to
* show an appropriate message for the newly selected node. Also,
* alert the selection listener for this panel. The listener will receive
* a path, if a collection has been selected. Otherwise, the listener
* will receive <code>null</code>.
*/
public void valueChanged(TreeSelectionEvent evt) {
// Get all nodes whose selection status has changed
TreePath[] paths = evt.getPaths();
for (int i = 0; i < paths.length; i++) {
if (evt.isAddedPath(i)) {
// process new selections
DefaultMutableTreeNode node;
node = (DefaultMutableTreeNode) (paths[i].getLastPathComponent());
Object o = node.getUserObject();
if (o instanceof TreeNodeWrapper) {
try {
TreeNodeWrapper wrapper = (TreeNodeWrapper) o;
Object data = wrapper.getData();
if (data instanceof Service) {
showService((Service) data);
alertListener(null);
} else if (data instanceof Workspace) {
showWorkspace((Workspace) data);
if (listener != null) {
alertListener(null);
}
} else if (data instanceof Collection) {
Collection c = (Collection) data;
showCollection(c);
alertListener(c.getLocation());
} else if (data instanceof SWORDEntry) {
showEntry((SWORDEntry) data);
alertListener(null);
} else {
details.setText("<html><body>unknown</body></html>");
alertListener(null);
}
} catch (Exception e) {
details.setText(
"<html><body>An error occurred. The message was: " + e.getMessage() + "</body></html>");
alertListener(null);
e.printStackTrace();
}
} else {
details.setText("<html><body>please select one of the other nodes</body></html>");
alertListener(null);
}
}
}
}
/**
* Notify the listener that there has been a change to the currently selected
* item in the tree.
*
* @param value The value to send to the listener.
*/
private void alertListener(String value) {
if (listener != null) {
listener.selected(value);
}
}
/**
* Add a new HTML table row to the specified StringBuffer. The label is displayed in
* the left column and the value is displayed in the right column.
*
* @param buffer The destination string buffer.
* @param label The label to add.
* @param value The corresponding value to add.
*/
private void addTableRow(StringBuffer buffer, String label, Object value) {
buffer.append("<tr bgcolor=\"#ffffff;\"><td>");
buffer.append(label);
buffer.append("</td><td>");
buffer.append(displayableValue(value));
buffer.append("</td></tr>");
}
/**
* Show the specified service data in the details panel.
*
* @param service The service node to display.
*/
private void showService(Service service) {
StringBuffer buffer = new StringBuffer();
buffer.append("<html>");
buffer.append("<body>");
buffer.append("<table border=\"1\" width=\"100%\">");
buffer.append("<tr bgcolor=\"#69a5c8;\"><td colspan=\"2\"><font size=\"+2\">Service Summary</font></td></tr>");
addTableRow(buffer, "SWORD Version", service.getVersion());
addTableRow(buffer, "NoOp Support ", service.isNoOp());
addTableRow(buffer, "Verbose Support ", service.isVerbose());
String maxSize = "";
// Commented out the following code as the client code is out of step with the
// Sword 'base' library and wont compile. - Robin Taylor.
//if ( service.maxUploadIsDefined() )
//{
// maxSize = "" + service.getMaxUploadSize() + "kB";
//}
//else
//{
maxSize = "undefined";
//}
addTableRow(buffer, "Max File Upload Size ", maxSize);
buffer.append("</table>");
buffer.append("</body>");
buffer.append("</html>");
details.setText(buffer.toString());
}
/**
* Display the workspace data in the details panel.
*
* @param workspace The workspace.
*/
private void showWorkspace(Workspace workspace) {
StringBuffer buffer = new StringBuffer();
buffer.append("<html>");
buffer.append("<body>");
buffer.append("<table border=\"1\" width=\"100%\">");
buffer
.append("<tr bgcolor=\"#69a5c8;\"><td colspan=\"2\"><font size=\"+2\">Workspace Summary</font></td></tr>");
addTableRow(buffer, "Workspace Title", workspace.getTitle());
buffer.append("</table>");
buffer.append("</body>");
buffer.append("</html>");
details.setText(buffer.toString());
}
/**
* Return the parameter unmodified if set, or the not defined text if null
* @param s
* @return s or ClientConstants.NOT_DEFINED_TEXT
*/
private Object displayableValue(Object s) {
if (null == s) {
return ClientConstants.NOT_DEFINED_TEXT;
} else {
return s;
}
}
/**
* Add a string within paragraph tags.
*
* @param buffer The buffer to add the message to.
* @param message The message to add.
*/
private void addPara(StringBuffer buffer, String message) {
buffer.append("<p>" + message + "</p>");
}
/**
* Show the specified collection data in the details panel.
*
* @param collection The collection data.
*/
private void showCollection(Collection collection) {
StringBuffer buffer = new StringBuffer();
buffer.append("<html>");
buffer.append("<body>");
if (collection == null) {
addPara(buffer, "Invalid Collection object. Unable to display details.");
} else {
buffer.append("<table border=\"1\" width=\"100%\">");
buffer.append(
"<tr bgcolor=\"#69a5c8;\"><td colspan=\"2\"><font size=\"+2\">Collection Summary</font></td></tr>");
addTableRow(buffer, "Collection location", collection.getLocation());
addTableRow(buffer, "Collection title", collection.getTitle());
addTableRow(buffer, "Abstract", collection.getAbstract());
addTableRow(buffer, "Collection Policy", collection.getCollectionPolicy());
addTableRow(buffer, "Treatment", collection.getTreatment());
addTableRow(buffer, "Mediation", collection.getMediation());
addTableRow(buffer, "Nested Service Document", collection.getService());
String[] accepts = collection.getAccepts();
StringBuilder acceptList = new StringBuilder();
if (accepts != null && accepts.length == 0) {
acceptList.append("None specified");
} else {
for (String s : accepts) {
acceptList.append(s).append("<br>");
}
}
addTableRow(buffer, "Accepts", acceptList.toString());
List<SwordAcceptPackaging> acceptsPackaging = collection.getAcceptPackaging();
StringBuilder acceptPackagingList = new StringBuilder();
for (Iterator i = acceptsPackaging.iterator(); i.hasNext(); ) {
SwordAcceptPackaging accept = (SwordAcceptPackaging) i.next();
acceptPackagingList.append(accept.getContent()).append(" (").append(accept.getQualityValue())
.append(")");
// add a , separator if there are any more items in the list
if (i.hasNext()) {
acceptPackagingList.append(", ");
}
}
addTableRow(buffer, "Accepts Packaging", acceptPackagingList.toString());
buffer.append("</table>");
}
buffer.append("</body>");
buffer.append("</html>");
details.setText(buffer.toString());
}
/**
* Display the contents of a Post entry in the display panel.
*
* @param entry The entry to display.
*/
private void showEntry(SWORDEntry entry) {
StringBuffer buffer = new StringBuffer();
buffer.append("<html>");
buffer.append("<body>");
if (entry == null) {
addPara(buffer, "Invalid Entry object. Unable to display details.");
} else {
buffer.append("<table border=\"1\" width=\"100%\">");
buffer
.append("<tr bgcolor=\"#69a5c8;\"><td colspan=\"2\"><font size=\"+2\">Entry Summary</font></td></tr>");
// process atom:title
String titleString = getTextConstructDetails(entry.getSummary());
addTableRow(buffer, "Title", titleString);
// process id
addTableRow(buffer, "ID", entry.getId());
// process updated
addTableRow(buffer, "Date Updated", entry.getUpdated());
String authorString = getAuthorDetails(entry.getAuthors());
addTableRow(buffer, "Authors", authorString);
// process summary
String summaryString = getTextConstructDetails(entry.getSummary());
addTableRow(buffer, "Summary", summaryString);
// process content
Content content = entry.getContent();
String contentString = "";
if (content == null) {
contentString = "Not defined.";
} else {
contentString += "Source: '" + content.getSource() + "', Type: '" +
content.getType() + "'";
}
addTableRow(buffer, "Content", contentString);
// process links
Iterator<Link> links = entry.getLinks();
StringBuffer linkBuffer = new StringBuffer();
for (; links.hasNext(); ) {
Link link = links.next();
linkBuffer.append("href: '");
linkBuffer.append(link.getHref());
linkBuffer.append("', href lang: '");
linkBuffer.append(link.getHreflang());
linkBuffer.append("', rel: '");
linkBuffer.append(link.getRel());
linkBuffer.append("')<br>");
}
if (linkBuffer.length() == 0) {
linkBuffer.append("Not defined");
}
addTableRow(buffer, "Links", linkBuffer.toString());
// process contributors
String contributorString = getContributorDetails(entry.getContributors());
addTableRow(buffer, "Contributors", contributorString);
// process source
String sourceString = "";
Generator generator = entry.getGenerator();
if (generator != null) {
sourceString += "Content: '" + generator.getContent() + "' <br>'";
sourceString += "Version: '" + generator.getVersion() + "' <br>'";
sourceString += "Uri: '" + generator.getUri() + "'";
} else {
sourceString += "No generator defined.";
}
addTableRow(buffer, "Generator", sourceString);
// process treatment
addTableRow(buffer, "Treatment", entry.getTreatment());
// process verboseDescription
addTableRow(buffer, "Verbose Description", entry.getVerboseDescription());
// process noOp
addTableRow(buffer, "NoOp", entry.isNoOp());
// process formatNamespace
addTableRow(buffer, "Packaging", entry.getPackaging());
// process userAgent
addTableRow(buffer, "User Agent", entry.getUserAgent());
buffer.append("</table>");
}
buffer.append("</body>");
buffer.append("</html>");
details.setText(buffer.toString());
}
/**
* Retrieve the details for a TextConstruct object.
*
* @param data The text construct object to display.
*
* @return Either 'Not defined' if the data is <code>null</code>, or
* details of the text content element.
*/
private String getTextConstructDetails(TextConstruct data) {
String summaryStr = "";
if (data == null) {
summaryStr = "Not defined";
} else {
summaryStr = "Content: '" + data.getContent() + "', Type: ";
if (data.getType() != null) {
summaryStr += "'" + data.getType().toString() + "'";
} else {
summaryStr += "undefined.";
}
}
return summaryStr;
}
/**
* Get the author details and insert them into a string.
*
* @param authors the list of authors to process.
*
* @return A string containing the list of authors.
*/
private String getAuthorDetails(Iterator<Author> authors) {
// process author
StringBuffer authorBuffer = new StringBuffer();
for (; authors.hasNext(); ) {
Author a = authors.next();
authorBuffer.append(getAuthorDetails(a));
}
if (authorBuffer.length() == 0) {
authorBuffer.append("Not defined");
}
return authorBuffer.toString();
}
/**
* Get the contributor details and insert them into a string.
*
* @param contributors The contributors.
*
* @return The string that lists the details of the contributors.
*/
private String getContributorDetails(Iterator<Contributor> contributors) {
// process author
StringBuffer authorBuffer = new StringBuffer();
for (; contributors.hasNext(); ) {
Contributor c = contributors.next();
authorBuffer.append(getAuthorDetails(c));
}
if (authorBuffer.length() == 0) {
authorBuffer.append("Not defined");
}
return authorBuffer.toString();
}
/**
* Build a string that describes the specified author.
*
* @param author The author.
*
* @return The string description.
*/
private String getAuthorDetails(Author author) {
// process author
StringBuffer authorBuffer = new StringBuffer();
authorBuffer.append(author.getName());
authorBuffer.append(" (email: '");
authorBuffer.append(author.getEmail());
authorBuffer.append("', uri: '");
authorBuffer.append(author.getUri());
authorBuffer.append("')<br>");
return authorBuffer.toString();
}
/**
* Process the deposit response and insert the details into the tree. If the url
* matches one of the collections in the tree, the deposit is added as a child
* node. Otherwise, the node is added as a child of the root.
*
* @param url The url of the collection that the file was posted to.
*
* @param response The details of the deposit.
*/
public void processDepositResponse(String url,
DepositResponse response) {
SWORDEntry entry = response.getEntry();
Object title = entry.getTitle();
if (title == null) {
title = "Undefined";
} else {
title = entry.getTitle().getContent();
}
TreeNodeWrapper wrapper = new TreeNodeWrapper(title.toString(), entry);
DefaultMutableTreeNode entryNode = new DefaultMutableTreeNode(wrapper);
DefaultMutableTreeNode newParentNode = top;
List<DefaultMutableTreeNode> nodes = getCollectionNodes();
for (DefaultMutableTreeNode node : nodes) {
Object o = node.getUserObject();
if (o instanceof TreeNodeWrapper) {
TreeNodeWrapper collectionWrapper = (TreeNodeWrapper) o;
Object data = collectionWrapper.getData();
if (data instanceof Collection) {
Collection col = (Collection) data;
String location = col.getLocation();
if (location != null && location.equals(url)) {
newParentNode = node;
break;
}
}
}
}
treeModel.insertNodeInto(entryNode, newParentNode, newParentNode.getChildCount());
services.scrollPathToVisible(new TreePath(entryNode.getPath()));
}
/**
* Get a list of all current collections displayed in the tree.
*
* @return An array of the URLs for the collections.
*/
public String[] getCollectionLocations() {
List<DefaultMutableTreeNode> nodes = getCollectionNodes();
String[] locations = new String[nodes.size()];
DefaultMutableTreeNode node;
for (int i = 0; i < nodes.size(); i++) {
node = nodes.get(i);
Object o = node.getUserObject();
if (o instanceof TreeNodeWrapper) {
TreeNodeWrapper collectionWrapper = (TreeNodeWrapper) o;
Object data = collectionWrapper.getData();
if (data instanceof Collection) {
Collection col = (Collection) data;
String location = col.getLocation();
if (location != null) {
locations[i] = location;
}
}
}
}
return locations;
}
/**
* Get a list of nodes that contain collections.
*
* @return A vector of the collection nodes.
*/
private List<DefaultMutableTreeNode> getCollectionNodes() {
List<DefaultMutableTreeNode> nodes = new ArrayList<DefaultMutableTreeNode>();
DefaultMutableTreeNode node;
Enumeration treeNodes = top.depthFirstEnumeration();
while (treeNodes.hasMoreElements()) {
node = (DefaultMutableTreeNode) treeNodes.nextElement();
Object o = node.getUserObject();
if (o instanceof TreeNodeWrapper) {
TreeNodeWrapper wrapper = (TreeNodeWrapper) o;
Object data = wrapper.getData();
if (data instanceof Collection) {
nodes.add(node);
}
}
}
return nodes;
}
}

View File

@@ -1,23 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Listener for any objects that want to be notified when a collection has been selected in the
* ServicePanel.
*
* @author Neil Taylor
*/
public interface ServiceSelectedListener {
/**
* Called to provide an update on whether the selected node is a Collection.
*
* @param collection The location of the collection. <code>null</code>, otherwise.
*/
public void selected(String collection);
}

View File

@@ -1,61 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.purl.sword.client;
/**
* Representation of the status code and message.
*
* @author Neil Taylor
*/
public class Status {
/**
* The status code.
*/
private int code;
/**
* The status message.
*/
private String message;
/**
* Create a new status message.
*
* @param code The code.
* @param message The message.
*/
public Status(int code, String message) {
this.code = code;
this.message = message;
}
/**
* Retrieve the code.
*
* @return The code.
*/
public int getCode() {
return code;
}
/**
* Get the message.
*
* @return The message.
*/
public String getMessage() {
return message;
}
/**
* Get a string representation of the status.
*/
public String toString() {
return "Code: " + code + ", Message: '" + message + "'";
}
}