
org.purl.sword.client.ServicePanel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dspace-sword Show documentation
Show all versions of dspace-sword Show documentation
DSpace SWORD Deposit Service Provider Extension
The newest version!
/**
* 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",
"Details
This panel will show the details for the currently " +
"selected item in the tree.
");
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 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 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 null
.
*/
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("unknown");
alertListener(null);
}
} catch (Exception e) {
details.setText(
"An error occurred. The message was: " + e.getMessage() + "");
alertListener(null);
e.printStackTrace();
}
} else {
details.setText("please select one of the other nodes");
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("");
buffer.append(label);
buffer.append(" ");
buffer.append(displayableValue(value));
buffer.append(" ");
}
/**
* 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("");
buffer.append("");
buffer.append("");
buffer.append("Service Summary ");
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("
");
buffer.append("");
buffer.append("");
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("");
buffer.append("");
buffer.append("");
buffer
.append("Workspace Summary ");
addTableRow(buffer, "Workspace Title", workspace.getTitle());
buffer.append("
");
buffer.append("");
buffer.append("");
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("" + message + "
");
}
/**
* 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("");
buffer.append("");
if (collection == null) {
addPara(buffer, "Invalid Collection object. Unable to display details.");
} else {
buffer.append("");
buffer.append(
"Collection Summary ");
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("
");
}
}
addTableRow(buffer, "Accepts", acceptList.toString());
List 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("
");
}
buffer.append("");
buffer.append("");
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("");
buffer.append("");
if (entry == null) {
addPara(buffer, "Invalid Entry object. Unable to display details.");
} else {
buffer.append("");
buffer
.append("Entry Summary ");
// 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 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("')
");
}
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() + "'
'";
sourceString += "Version: '" + generator.getVersion() + "'
'";
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("
");
}
buffer.append("");
buffer.append("");
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 null
, 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 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 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("')
");
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 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 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 getCollectionNodes() {
List nodes = new ArrayList();
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;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy