Java tutorial
/* * Copyright 2012 Johns Hopkins University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.dataconservancy.dcs.ingest.ui.client; import java.util.ArrayList; import java.util.List; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.History; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DecoratedTabPanel; import com.google.gwt.user.client.ui.DialogBox; import com.google.gwt.user.client.ui.FileUpload; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FormPanel; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.Hidden; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Hyperlink; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.TabPanel; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent; import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler; import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; import com.google.gwt.xml.client.Element; import com.google.gwt.xml.client.NodeList; import com.google.gwt.xml.client.XMLParser; import org.dataconservancy.dcs.ingest.ui.client.model.Package; // TODO use i8n stuff for ui labels /** * User interface. */ public class Application implements EntryPoint { public static final String FILE_UPLOAD_URL = GWT.getModuleBaseURL() + "fileupload"; private final DepositServiceAsync deposit = GWT.create(DepositService.class); private Panel content; private Panel sidebar; private DepositConfig depositConfig; private String deposit_endpoint = "http://dcservice.dataconservancy.org:8080/dcs/deposit/"; private String deposit_user = ""; private String deposit_pass = ""; private TabPanel collections; private TabPanel files; private TabPanel dus; private List<String> fileids, colids, duids; private int colseq, fileseq, duseq; public void onModuleLoad() { Grid main = new Grid(3, 2); main.setStyleName("Main"); RootPanel.get().add(main); sidebar = new VerticalPanel(); content = new FlowPanel(); collections = new DecoratedTabPanel(); files = new DecoratedTabPanel(); dus = new DecoratedTabPanel(); this.fileids = new ArrayList<String>(); this.duids = new ArrayList<String>(); this.colids = new ArrayList<String>(); HorizontalPanel header = new HorizontalPanel(); Panel footer = new FlowPanel(); CellFormatter fmt = main.getCellFormatter(); fmt.setStylePrimaryName(0, 0, "TopHeaderLeft"); fmt.setStylePrimaryName(0, 1, "TopHeader"); fmt.setStylePrimaryName(1, 0, "Sidebar"); fmt.setStylePrimaryName(1, 1, "Content"); fmt.setStylePrimaryName(2, 0, "FooterLeft"); fmt.setStylePrimaryName(2, 1, "Footer"); Label toptext = Util.label("Ingest User Interface", "TopHeaderText"); header.add(toptext); header.setCellVerticalAlignment(toptext, HasVerticalAlignment.ALIGN_BOTTOM); footer.add(new HTML("<a href='http://dataconservancy.org/'>http://dataconservancy.org/</a>")); main.setWidget(0, 0, new Image(GWT.getModuleBaseURL() + "simply_modern_logo.png")); main.setWidget(0, 1, header); main.setWidget(1, 0, sidebar); main.setWidget(1, 1, content); main.setWidget(2, 1, footer); History.addValueChangeHandler(new ValueChangeHandler<String>() { public void onValueChange(ValueChangeEvent<String> event) { historyChanged(event.getValue()); } }); History.newItem(State.HOME.toToken(), false); History.fireCurrentHistoryState(); } private static Widget createSidebarHyperlink(String name, String token) { if (History.getToken().startsWith(token)) { Label l = new Label(name); l.addStyleName("SidebarSelected"); return l; } else { return new Hyperlink(name, token); } } private String nextCollectionId() { return "col" + ++colseq; } private String nextFileId() { return "file" + ++fileseq; } private String nextDeliverableUnitId() { return "du" + ++duseq; } private void historyChanged(String token) { if (token.isEmpty()) { return; } State action = State.fromToken(token); List<String> args = State.tokenArguments(token); if (action == null) { handleHistoryTokenError(token); return; } if (action == State.HOME) { viewHome(); } else if (depositConfig == null) { History.newItem(State.HOME.toToken(), false); viewHome(); } else if (action == State.FILE) { if (args.size() != 0) { handleHistoryTokenError(token); return; } viewFiles(); } else if (action == State.COLLECTION) { if (args.size() != 0) { handleHistoryTokenError(token); return; } viewCollections(); } else if (action == State.DELIVERABLE_UNIT) { if (args.size() != 0) { handleHistoryTokenError(token); return; } viewDeliverableUnits(); } else if (action == State.SUBMIT) { if (args.size() != 0) { handleHistoryTokenError(token); return; } viewSubmission(); } else { handleHistoryTokenError(token); return; } setupSidebar(); } private void viewHome() { content.clear(); Label explain = new Label("The DCS Ingest UI allows simple SIPs to be created and uploaded."); explain.setStylePrimaryName("Explanation"); content.add(explain); if (depositConfig == null) { content.add(new Label("Login")); final FlexTable table = Util.createTable("Deposit endpoint:", "User:", "Pass:"); final TextBox end_tb = new TextBox(); end_tb.setWidth("40em"); final TextBox user_tb = new TextBox(); final PasswordTextBox pass_tb = new PasswordTextBox(); end_tb.setText(deposit_endpoint); user_tb.setText(deposit_user); pass_tb.setText(deposit_pass); Util.addColumn(table, end_tb, user_tb, pass_tb); content.add(table); Button login = new Button("Login"); login.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { AsyncCallback<DepositConfig> cb = new AsyncCallback<DepositConfig>() { public void onSuccess(DepositConfig result) { depositConfig = result; deposit_endpoint = end_tb.getText(); deposit_user = user_tb.getText(); deposit_pass = pass_tb.getText(); viewHome(); } public void onFailure(Throwable error) { Window.alert("Failed to login: " + error.getMessage()); } }; deposit.login(end_tb.getText(), user_tb.getText(), pass_tb.getText(), cb); } }); content.add(login); } else { content.add(new Label("Logged in to: " + deposit_endpoint)); } } private void setupSidebar() { sidebar.clear(); sidebar.add(createSidebarHyperlink("Home", State.HOME.toToken())); sidebar.add(createSidebarHyperlink("Files", State.FILE.toToken())); sidebar.add(createSidebarHyperlink("Collections", State.COLLECTION.toToken())); sidebar.add(createSidebarHyperlink("Deliverable Units", State.DELIVERABLE_UNIT.toToken())); sidebar.add(createSidebarHyperlink("Submission", State.SUBMIT.toToken())); } private void handleHistoryTokenError(String token) { Window.alert("Error parsing action: " + token); } private void viewFiles() { content.clear(); Label explain = new Label( "Upload local files for inclusion to the SIP. Remote files accessible by a URL may also be added. Files with the same technical enviroment in the same Deliverable Unit will be put in the same Manifestation."); explain.setStylePrimaryName("Explanation"); content.add(explain); if (files.getWidgetCount() > 0) { files.selectTab(0); } else { files.setVisible(false); } Button upload = new Button("Upload local file"); Button uploadremote = new Button("Add remote file"); Button remove = new Button("Remove"); final HorizontalPanel buttons = new HorizontalPanel(); buttons.setSpacing(5); buttons.add(upload); buttons.add(uploadremote); buttons.add(remove); content.add(files); content.add(buttons); remove.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { int tab = files.getTabBar().getSelectedTab(); if (tab != -1) { files.remove(tab); fileids.remove(tab); if (files.getWidgetCount() > 0) { files.selectTab(0); } else { files.setVisible(false); } } } }); uploadremote.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { files.setVisible(true); String id = nextFileId(); fileids.add(id); files.add(new FileEditor(id, "name", "http://"), id); files.selectTab(files.getWidgetCount() - 1); } }); upload.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { displayUploadFileDialog(); } }); } private void displayUploadFileDialog() { final DialogBox db = new DialogBox(false, true); Panel panel = new FlowPanel(); db.setAnimationEnabled(true); db.setText("Upload local file"); db.setWidget(panel); db.center(); final HorizontalPanel buttons = new HorizontalPanel(); buttons.setSpacing(5); Button upload = new Button("Upload"); Button cancel = new Button("Cancel"); buttons.add(upload); buttons.add(cancel); final FormPanel form = new FormPanel(); FlowPanel formcontents = new FlowPanel(); form.add(formcontents); final FileUpload upfile = new FileUpload(); upfile.setName("file"); Hidden depositurl = new Hidden("depositurl"); depositurl.setValue(depositConfig.fileUploadUrl()); formcontents.add(upfile); formcontents.add(depositurl); form.setMethod(FormPanel.METHOD_POST); form.setEncoding(FormPanel.ENCODING_MULTIPART); form.setAction(FILE_UPLOAD_URL); panel.add(new Label("Uploaded files will be included in the SIP.")); panel.add(form); panel.add(buttons); upload.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { form.submit(); } }); cancel.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { db.hide(); } }); form.addSubmitCompleteHandler(new SubmitCompleteHandler() { public void onSubmitComplete(SubmitCompleteEvent event) { if (event.getResults() == null) { Window.alert("File upload failed"); db.hide(); return; } String[] parts = event.getResults().split("\\^"); if (parts.length != 4) { Window.alert("File upload failed: " + event.getResults()); db.hide(); return; } String filesrc = parts[1].trim(); // TODO String fileatomurl = parts[2].trim(); files.setVisible(true); String id = nextFileId(); fileids.add(id); files.add(new FileEditor(id, upfile.getFilename(), filesrc), id); files.selectTab(files.getWidgetCount() - 1); db.hide(); } }); } private void viewCollections() { content.clear(); content.add(Util.label("Collections help group Deliverable Units.", "Explanation")); content.add(collections); HorizontalPanel toolbar = new HorizontalPanel(); Button remove = new Button("Remove collection"); Button add = new Button("Add collection"); toolbar.add(add); toolbar.add(remove); toolbar.setSpacing(5); content.add(toolbar); if (collections.getWidgetCount() > 0) { collections.selectTab(0); } else { collections.setVisible(false); } remove.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { int tab = collections.getTabBar().getSelectedTab(); if (tab != -1) { collections.remove(tab); colids.remove(tab); if (collections.getWidgetCount() > 0) { collections.selectTab(0); } else { collections.setVisible(false); } } } }); add.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { collections.setVisible(true); String id = nextCollectionId(); colids.add(id); collections.add(new CollectionEditor(id, colids), id); collections.selectTab(collections.getWidgetCount() - 1); } }); } private void viewDeliverableUnits() { content.clear(); content.add(Util.label("A Deliverable Unit is a semantically meaningfull container for files and metadata.", "Explanation")); content.add(dus); HorizontalPanel toolbar = new HorizontalPanel(); Button remove = new Button("Remove Deliverable Unit"); Button add = new Button("Add Deliverable Unit"); toolbar.add(add); toolbar.add(remove); toolbar.setSpacing(5); content.add(toolbar); if (dus.getWidgetCount() > 0) { dus.selectTab(0); } else { dus.setVisible(false); } remove.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { int tab = dus.getTabBar().getSelectedTab(); if (tab != -1) { dus.remove(tab); duids.remove(tab); if (dus.getWidgetCount() > 0) { dus.selectTab(0); } else { dus.setVisible(false); } } } }); add.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { dus.setVisible(true); String id = nextDeliverableUnitId(); duids.add(id); dus.add(new DeliverableUnitEditor(id, fileids, duids, colids), id); dus.selectTab(dus.getWidgetCount() - 1); } }); } private Package constructPackage() { Package pkg = new Package(); for (int i = 0; i < collections.getWidgetCount(); i++) { CollectionEditor ed = (CollectionEditor) collections.getWidget(i); pkg.collections().add(ed.getCollection()); } for (int i = 0; i < dus.getWidgetCount(); i++) { DeliverableUnitEditor ed = (DeliverableUnitEditor) dus.getWidget(i); pkg.deliverableUnits().add(ed.getDeliverableUnit()); } for (int i = 0; i < files.getWidgetCount(); i++) { FileEditor ed = (FileEditor) files.getWidget(i); pkg.files().add(ed.getFile()); } return pkg; } private void viewSubmission() { content.clear(); Label explain = new Label( "Constructs a SIP and submits it to the DCS. A successful submission will return an atom feed of the ingestion status."); explain.setStylePrimaryName("Explanation"); Button submit = new Button("Submit SIP"); final FlowPanel status = new FlowPanel(); status.setStylePrimaryName("SubmissionStatus"); content.add(explain); content.add(status); content.add(submit); submit.addClickHandler(new ClickHandler() { public void onClick(ClickEvent arg0) { status.clear(); status.add(new Label("Submitting SIP to: " + depositConfig.sipDepositUrl() + " ...")); Package pkg = constructPackage(); deposit.submitSIP(depositConfig.sipDepositUrl(), deposit_user, deposit_pass, pkg, new AsyncCallback<String>() { public void onFailure(Throwable error) { status.clear(); status.add(new Label("Error submitting SIP:")); TextArea text = new TextArea(); text.setText(error.getMessage()); text.setReadOnly(true); text.setWidth("50em"); text.setHeight("10em"); ScrollPanel sp = new ScrollPanel(text); status.add(sp); } public void onSuccess(String result) { status.clear(); com.google.gwt.xml.client.Document doc = XMLParser.parse(result); NodeList list = doc.getElementsByTagName("link"); for (int i = 0; i < list.getLength(); i++) { Element e = (Element) list.item(i); String url = e.getAttribute("href"); if (url != null) { status.add(new Anchor("Processing status feed", url, "_blank")); break; } } TextArea text = new TextArea(); text.setText(result); text.setReadOnly(true); text.setWidth("50em"); text.setHeight("10em"); ScrollPanel sp = new ScrollPanel(text); status.add(Util.label("Atom XML document", "SubSectionHeader")); status.add(sp); } }); } }); } }