X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fws%2Frest%2FRestJobThread.java;h=e397c798bd42d0d86196d5d59eac20f5e808f47b;hb=9f70ff4b6d193b340031997634c9e3602486bc8e;hp=799c7b4c3c9a34ea3e4d909d915f5deaf70087db;hpb=4a3c64c3d8e65cc34ce36dd2cf8a575eea6d5493;p=jalview.git diff --git a/src/jalview/ws/rest/RestJobThread.java b/src/jalview/ws/rest/RestJobThread.java index 799c7b4..e397c79 100644 --- a/src/jalview/ws/rest/RestJobThread.java +++ b/src/jalview/ws/rest/RestJobThread.java @@ -1,3 +1,23 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.ws.rest; import jalview.bin.Cache; @@ -6,7 +26,7 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.Annotation; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; @@ -16,6 +36,7 @@ import jalview.gui.WebserviceInfo; import jalview.io.NewickFile; import jalview.io.packed.JalviewDataset; import jalview.io.packed.JalviewDataset.AlignmentSet; +import jalview.util.MessageManager; import jalview.ws.AWSThread; import jalview.ws.AWsJob; @@ -23,11 +44,9 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.ArrayList; -import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Map.Entry; -import java.util.Vector; import org.apache.axis.transport.http.HTTPConstants; import org.apache.http.Header; @@ -40,8 +59,6 @@ import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; public class RestJobThread extends AWSThread @@ -71,8 +88,8 @@ public class RestJobThread extends AWSThread { jobs = new RestJob[1]; jobs[0] = new RestJob(0, this, - restClient._input.getVisibleAlignment(restClient.service - .getGapCharacter()), + restClient._input.getVisibleAlignment( + restClient.service.getGapCharacter()), restClient._input.getVisibleContigs()); // need a function to get a range on a view/alignment and return both // annotation, groups and selection subsetted to just that region. @@ -82,15 +99,14 @@ public class RestJobThread extends AWSThread { int[] viscontig = restClient._input.getVisibleContigs(); AlignmentI[] viscontigals = restClient._input - .getVisibleContigAlignments(restClient.service - .getGapCharacter()); + .getVisibleContigAlignments( + restClient.service.getGapCharacter()); if (viscontigals != null && viscontigals.length > 0) { jobs = new RestJob[viscontigals.length]; for (int j = 0; j < jobs.length; j++) { - int[] visc = new int[] - { viscontig[j * 2], viscontig[j * 2 + 1] }; + int[] visc = new int[] { viscontig[j * 2], viscontig[j * 2 + 1] }; if (j != 0) { jobs[j] = new RestJob(j, this, viscontigals[j], visc); @@ -155,9 +171,13 @@ public class RestJobThread extends AWSThread private String getStage(Stage stg) { if (stg == Stage.SUBMIT) + { return "submitting "; + } if (stg == Stage.POLL) + { return "checking status of "; + } return (" being confused about "); } @@ -194,9 +214,6 @@ public class RestJobThread extends AWSThread protected void doHttpReq(Stage stg, RestJob rj, String postUrl) throws Exception { - StringBuffer respText = new StringBuffer(); - // con.setContentHandlerFactory(new - // jalview.ws.io.mime.HttpContentHandler()); HttpRequestBase request = null; String messages = ""; if (stg == Stage.SUBMIT) @@ -211,8 +228,8 @@ public class RestJobThread extends AWSThread { if (input.getValue().validFor(rj)) { - postentity.addPart(input.getKey(), input.getValue() - .formatForInput(rj)); + postentity.addPart(input.getKey(), + input.getValue().formatForInput(rj)); } else { @@ -231,15 +248,16 @@ public class RestJobThread extends AWSThread { DefaultHttpClient httpclient = new DefaultHttpClient(); - HttpContext localContext = new BasicHttpContext(); HttpResponse response = null; try { response = httpclient.execute(request); } catch (ClientProtocolException he) { - rj.statMessage = "Web Protocol Exception when attempting to " - + getStage(stg) + "Job. See Console output for details."; + rj.statMessage = "Web Protocol Exception when " + getStage(stg) + + "Job.
Problematic url was " + request.getURI() + + "
See Console output for details."; rj.setAllowedServerExceptions(0);// unrecoverable; rj.error = true; Cache.log.fatal("Unexpected REST Job " + getStage(stg) @@ -247,8 +265,10 @@ public class RestJobThread extends AWSThread throw (he); } catch (IOException e) { - rj.statMessage = "IO Exception when attempting to " - + getStage(stg) + "Job. See Console output for details."; + rj.statMessage = "IO Exception when " + getStage(stg) + + "Job.
Problematic url was " + request.getURI() + + "
See Console output for details."; Cache.log.warn("IO Exception for REST Job " + getStage(stg) + "exception for URL " + rj.rsd.postUrl); @@ -261,42 +281,19 @@ public class RestJobThread extends AWSThread Cache.log.debug("Processing result set."); processResultSet(rj, response, request); break; + case 202: - rj.statMessage = "
Job submitted successfully. Results available at this URL:\n" - + "" - + rj.getJobId() - + "
"; - rj.running = true; + markJobAsRunning(rj); break; + + case 201: + // Created - redirect may be present. Fallthrough to 302 case 302: - Header[] loc; - if (!rj.isSubmitted() - && (loc = response - .getHeaders(HTTPConstants.HEADER_LOCATION)) != null - && loc.length > 0) - { - if (loc.length > 1) - { - Cache.log - .warn("Ignoring additional " - + (loc.length - 1) - + " location(s) provided in response header ( next one is '" - + loc[1].getValue() + "' )"); - } - rj.setJobId(loc[0].getValue()); - rj.setSubmitted(true); - } + extractJobId(rj, response); completeStatus(rj, response); break; case 500: - // Failed. - rj.setSubmitted(true); - rj.setAllowedServerExceptions(0); - rj.setSubjobComplete(true); - rj.error = true; - rj.running = false; + markAsFailed(rj, response); completeStatus(rj, response, "" + getStage(stg) + "failed. Reason below:\n"); break; @@ -305,9 +302,16 @@ public class RestJobThread extends AWSThread // TODO: deal with all other HTTP response codes from server. Cache.log.warn("Unhandled response status when " + getStage(stg) + "for " + postUrl + ": " + response.getStatusLine()); + rj.error = true; + rj.setAllowedServerExceptions(0); + rj.setSubjobComplete(true); + rj.setSubmitted(true); try { - response.getEntity().consumeContent(); + completeStatus(rj, response, "" + getStage(stg) + + " resulted in an unexpected server response.
Url concerned was " + request.getURI() + + "
Filtered response content below:
"); } catch (IOException e) { Cache.log.debug("IOException when consuming unhandled response", @@ -318,6 +322,64 @@ public class RestJobThread extends AWSThread } } + private void markAsFailed(RestJob rj, HttpResponse response) + { + // Failed. + rj.setSubmitted(true); + rj.setAllowedServerExceptions(0); + rj.setSubjobComplete(true); + rj.error = true; + rj.running = false; + } + + /** + * set the jobRunning flag and post a link to the physical result page encoded + * in rj.getJobId() + * + * @param rj + */ + private void markJobAsRunning(RestJob rj) + { + rj.statMessage = "
Job submitted successfully. Results available at this URL:\n" + + "" + + rj.getJobId() + + "
"; + rj.running = true; + } + + /** + * extract the job ID URL from the redirect page. Does nothing if job is + * already running. + * + * @param rj + * @param response + */ + private void extractJobId(RestJob rj, HttpResponse response) + { + Header[] loc; + if (!rj.isSubmitted()) + { + + // redirect URL - typical for IBIVU type jobs. + if ((loc = response.getHeaders(HTTPConstants.HEADER_LOCATION)) != null + && loc.length > 0) + { + if (loc.length > 1) + { + Cache.log + .warn("Ignoring additional " + + (loc.length - 1) + + " location(s) provided in response header ( next one is '" + + loc[1].getValue() + "' )"); + } + rj.setJobId(loc[0].getValue()); + rj.setSubmitted(true); + } + } + } + /** * job has completed. Something valid should be available from con * @@ -377,7 +439,7 @@ public class RestJobThread extends AWSThread int body = f.indexOf(" -1) { - content.delete(0, f.indexOf(">", body)); + content.delete(0, f.indexOf(">", body) + 1); } if (body > -1 && sb.length() > 0) { @@ -405,16 +467,15 @@ public class RestJobThread extends AWSThread { System.err.println("Debug RestJob: Posting Job"); doPost((RestJob) job); - } - catch (NoValidInputDataException erex) + } catch (NoValidInputDataException erex) { job.setSubjobComplete(true); job.setSubmitted(true); - ((RestJob)job).statMessage="
It looks like there was a problem with the data sent to the service :
"+erex.getMessage()+"\n"; - ((RestJob)job).error=true; - - } - catch (Exception ex) + ((RestJob) job).statMessage = "
It looks like there was a problem with the data sent to the service :
" + + erex.getMessage() + "\n"; + ((RestJob) job).error = true; + + } catch (Exception ex) { job.setSubjobComplete(true); job.setAllowedServerExceptions(-1); @@ -446,14 +507,20 @@ public class RestJobThread extends AWSThread } catch (Error ex) { - Cache.log.warn("Failed to finish parsing data for job " - + rj.getJobId()); + Cache.log.warn( + "Failed to finish parsing data for job " + rj.getJobId()); ex.printStackTrace(); } catch (Exception ex) { - Cache.log.warn("Failed to finish parsing data for job " - + rj.getJobId()); + Cache.log.warn( + "Failed to finish parsing data for job " + rj.getJobId()); ex.printStackTrace(); + } finally + { + rj.error = true; + rj.statMessage = "Error whilst parsing data for this job.
URL for job response is :" + rj.resSet.getUrl() + + "
"; } } } @@ -567,7 +634,7 @@ public class RestJobThread extends AWSThread // total number of distinct alignment sets generated by job set. int numAlSets = 0, als = 0; List destAls = new ArrayList(); - List destColsel = new ArrayList(); + List destColsel = new ArrayList(); List> trees = new ArrayList>(); do @@ -673,7 +740,7 @@ public class RestJobThread extends AWSThread RestJob rj = (RestJob) jobs[nrj]; int contigs[] = input.getVisibleContigs(); AlignmentI destAl = null; - jalview.datamodel.ColumnSelection destCs = null; + jalview.datamodel.HiddenColumns destHCs = null; // Resolve destAl for this data. if (als == 0 && rj.isInputContextModified()) { @@ -689,10 +756,10 @@ public class RestJobThread extends AWSThread if (!restClient.isAlignmentModified() && merge) { destAl = restClient.av.getAlignment(); - destCs = restClient.av.getColumnSelection(); - resultDest - .add(restClient.isShowResultsInNewView() ? AddDataTo.newView - : AddDataTo.currentView); + destHCs = restClient.av.getAlignment().getHiddenColumns(); + resultDest.add(restClient.isShowResultsInNewView() + ? AddDataTo.newView + : AddDataTo.currentView); destPanels.add(restClient.recoverAlignPanelForView()); } else @@ -700,15 +767,15 @@ public class RestJobThread extends AWSThread newAlignment = true; // recreate the input alignment data Object[] idat = input - .getAlignmentAndColumnSelection(gapCharacter); + .getAlignmentAndHiddenColumns(gapCharacter); destAl = new Alignment((SequenceI[]) idat[0]); - destCs = (ColumnSelection) idat[1]; + destHCs = (HiddenColumns) idat[1]; resultDest.add(AddDataTo.newAlignment); // but do not add to the alignment panel list - since we need to // create a whole new alignFrame set. } destAls.add(destAl); - destColsel.add(destCs); + destColsel.add(destHCs); } } else @@ -721,13 +788,13 @@ public class RestJobThread extends AWSThread { // TODO: decide if multiple multiple alignments returned by // non-vseparable services are allowed. - Cache.log - .warn("dealing with multiple alignment products returned by non-vertically separable service."); + Cache.log.warn( + "dealing with multiple alignment products returned by non-vertically separable service."); } // recover reference to last alignment created for this rest frame // ready for extension destAl = destAls.get(als); - destCs = destColsel.get(als); + destHCs = destColsel.get(als); } else { @@ -756,14 +823,16 @@ public class RestJobThread extends AWSThread newview = input.getUpdatedView(rseqs, orders, gapCharacter); } destAl = new Alignment((SequenceI[]) newview[0]); - destCs = (ColumnSelection) newview[1]; + destHCs = (HiddenColumns) newview[1]; newAlignment = true; // TODO create alignment from result data with propagated // references. destAls.add(destAl); - destColsel.add(destCs); + destColsel.add(destHCs); resultDest.add(AddDataTo.newAlignment); - throw new Error("Impl. Error! TODO: "); + throw new Error( + MessageManager.getString("error.implementation_error") + + "TODO: "); } } /** @@ -808,7 +877,9 @@ public class RestJobThread extends AWSThread visgrps.add(exsg); exsg.setStartRes(sg.getStartRes() + contigs[ncnt]); exsg.setEndRes(sg.getEndRes() + contigs[ncnt]); - } else { + } + else + { recovered = true; } // now replace any references from the result set with @@ -817,10 +888,8 @@ public class RestJobThread extends AWSThread // TODO: cope with recovering hidden sequences from // resultContext { - Vector sqs = sg.getSequences(null); - for (int sqsi = 0, iSize = sqs.size(); sqsi < iSize; sqsi++) + for (SequenceI oseq : sg.getSequences(null)) { - SequenceI oseq = (SequenceI) sqs.get(sqsi); SequenceI nseq = getNewSeq(oseq, rseqs[nrj], ordermap[nrj], destAl); if (nseq != null) @@ -833,8 +902,8 @@ public class RestJobThread extends AWSThread } else { - Cache.log - .warn("Couldn't resolve original sequence for new sequence."); + Cache.log.warn( + "Couldn't resolve original sequence for new sequence."); } } if (sg.hasSeqrep()) @@ -856,8 +925,8 @@ public class RestJobThread extends AWSThread { // adjust boundaries of recovered group w.r.t. new group being // merged on to original alignment. - int start = sg.getStartRes() + contigs[ncnt], end = sg - .getEndRes() + contigs[ncnt]; + int start = sg.getStartRes() + contigs[ncnt], + end = sg.getEndRes() + contigs[ncnt]; if (start < exsg.getStartRes()) { exsg.setStartRes(start); @@ -911,8 +980,8 @@ public class RestJobThread extends AWSThread grass = groupNames.get(alan[nrj][an].groupRef.getName()); if (grass == null) { - Cache.log - .error("Couldn't relocate group referemce for group " + Cache.log.error( + "Couldn't relocate group referemce for group " + alan[nrj][an].groupRef.getName()); } } @@ -938,12 +1007,15 @@ public class RestJobThread extends AWSThread visan.sequenceRef = sqass; visAlAn.add(visan); } - if (contigs[ncnt]+alan[nrj][an].annotations.length>visan.annotations.length) + if (contigs[ncnt] + + alan[nrj][an].annotations.length > visan.annotations.length) { // increase width of annotation row - Annotation[] newannv = new Annotation[contigs[ncnt]+alan[nrj][an].annotations.length]; - System.arraycopy(visan.annotations, 0, newannv, 0, visan.annotations.length); - visan.annotations=newannv; + Annotation[] newannv = new Annotation[contigs[ncnt] + + alan[nrj][an].annotations.length]; + System.arraycopy(visan.annotations, 0, newannv, 0, + visan.annotations.length); + visan.annotations = newannv; } // now copy local annotation data into correct position System.arraycopy(alan[nrj][an].annotations, 0, @@ -959,8 +1031,8 @@ public class RestJobThread extends AWSThread { // TODO: process each newick file, lifting over sequence refs to // current alignment, if necessary. - Cache.log - .error("Tree recovery from restjob not yet implemented."); + Cache.log.error( + "Tree recovery from restjob not yet implemented."); } } } @@ -996,9 +1068,11 @@ public class RestJobThread extends AWSThread for (AddDataTo action : resultDest) { AlignmentI destal; - ColumnSelection destcs; - String alTitle = restClient.service.details.Action + " using " - + restClient.service.details.Name + " on "+restClient.viewTitle; + HiddenColumns destcs; + String alTitle = MessageManager + .formatMessage("label.webservice_job_title_on", new String[] + { restClient.service.details.Action, + restClient.service.details.Name, restClient.viewTitle }); switch (action) { case newAlignment: @@ -1006,7 +1080,8 @@ public class RestJobThread extends AWSThread destcs = destColsel.get(als); destaf = new AlignFrame(destal, destcs, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - PaintRefresher.Refresh(destaf, destaf.getViewport().getSequenceSetId()); + PaintRefresher.Refresh(destaf, + destaf.getViewport().getSequenceSetId()); // todo transfer any feature settings and colouring /* * destaf.getFeatureRenderer().transferSettings(this.featureSettings); @@ -1026,7 +1101,8 @@ public class RestJobThread extends AWSThread * i++) { af.addSortByOrderMenuItem( WebServiceName + ((String) * names.get(i)) + " Ordering", (AlignmentOrder) alorders.get(i)); } } } */ - // TODO: modify this and previous alignment's title if many alignments have been returned. + // TODO: modify this and previous alignment's title if many alignments + // have been returned. Desktop.addInternalFrame(destaf, alTitle, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); @@ -1133,8 +1209,8 @@ public class RestJobThread extends AWSThread { if (start + width < end) { - blocks[c][s] = sequenceIs[s].getSubSequence(start, start - + width); + blocks[c][s] = sequenceIs[s].getSubSequence(start, + start + width); } else { @@ -1206,8 +1282,8 @@ public class RestJobThread extends AWSThread */ public boolean isValid() { - ArrayList _warnings=new ArrayList(); - boolean validt=true; + ArrayList _warnings = new ArrayList(); + boolean validt = true; if (jobs != null) { for (RestJob rj : (RestJob[]) jobs) @@ -1216,42 +1292,48 @@ public class RestJobThread extends AWSThread { // invalid input for this job System.err.println("Job " + rj.getJobnum() - + " has invalid input. ( "+rj.getStatus()+")"); + + " has invalid input. ( " + rj.getStatus() + ")"); if (rj.hasStatus() && !_warnings.contains(rj.getStatus())) { _warnings.add(rj.getStatus()); } - validt=false; + validt = false; } } } if (!validt) { warnings = ""; - for (String st : _warnings) { - if (warnings.length()>0) { warnings+="\n"; + for (String st : _warnings) + { + if (warnings.length() > 0) + { + warnings += "\n"; } warnings += st; - + } } return validt; } protected String warnings; + public boolean hasWarnings() { // TODO Auto-generated method stub - return warnings!=null && warnings.length()>0; + return warnings != null && warnings.length() > 0; } /** * get any informative messages about why the job thread couldn't start. + * * @return */ public String getWarnings() { - return isValid() ? "Job can be started. No warnings." : hasWarnings() ? warnings : ""; + return isValid() ? "Job can be started. No warnings." + : hasWarnings() ? warnings : ""; } }