1 /* 2 * Copyright 2008, 2009 Ange Optimization ApS 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package eu.simuline.octave.exec; 17 18 import java.io.IOException; 19 import java.io.Writer; 20 import java.util.concurrent.Callable; 21 22 import eu.simuline.octave.exception.OctaveIOException; 23 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 27 /** 28 * {@link Callable} that writes scripts to the octave process. 29 * Used in {@link OctaveExec#evalRW(WriteFunctor, ReadFunctor)} only. 30 * This is complementary to {@link OctaveReaderCallable}. 31 */ 32 final class OctaveWriterCallable implements Callable<Void> { 33 34 private static final Log LOG = LogFactory 35 .getLog(OctaveWriterCallable.class); 36 37 static final String MSG_IOE_WRITE = 38 "IOException from WriteFunctor"; 39 40 static final String MSG_IOE_SPACER = 41 "IOException when writing spacer"; 42 43 /** 44 * The writer for scripts passed to octave. 45 * This is nothing but {@link OctaveExec#processWriter}. 46 */ 47 private final Writer processWriter; 48 49 /** 50 * The functor the writing task is delegated to. 51 */ 52 private final WriteFunctor writeFunctor; 53 54 /** 55 * A string essentially consisting of a unique hashvalue. 56 * It is printed to {@link #processWriter} 57 * after having applied {@link #writeFunctor}. 58 * That way the according {@link OctaveReaderCallable} 59 * detects the end of the read sequence from the octave process. 60 */ 61 private final String spacer; 62 63 // TBC: strictly speaking, 64 // this goes wrong with a small but positive probability. 65 /** 66 * Creates a new OctaveWriterCallable with method {@link #call()} 67 * delegating writing 68 * 69 * @param processWriter 70 * the writer used for writing. 71 * @param writeFunctor 72 * the functor the writing process is delegated to. 73 * @param spacer 74 * a string essentially consisting of a unique hashvalue 75 * printed after applying the write functor. 76 * This indicates the end of the sunbsequent according reading process 77 * in {@link OctaveExec#evalRW(WriteFunctor, ReadFunctor)}. 78 */ 79 OctaveWriterCallable(final Writer processWriter, 80 final WriteFunctor writeFunctor, 81 final String spacer) { 82 this.processWriter = processWriter; 83 this.writeFunctor = writeFunctor; 84 this.spacer = spacer; 85 } 86 87 /** 88 * Calling writes to {@link #processWriter} 89 * representing the octave process: 90 * first according to {@link #writeFunctor}, 91 * i.e. delegates to {@link WriteFunctor#doWrites(Writer)}, 92 * then writes <code>printf</code> of {@link #spacer} and then flush. 93 * That way, {@link OctaveReaderCallable#call()} knows, that reading is completed, 94 * as soon as the spacer is detected. 95 * Exceptions are logged on {@link #LOG}. 96 * 97 * @throws OctaveIOException 98 * if the underlying {@link #writeFunctor} or {@link #processWriter} 99 * throws an {@link IOException}. 100 */ 101 @Override 102 public Void call() { 103 // Write to process 104 try { 105 this.writeFunctor.doWrites(this.processWriter); 106 } catch (final IOException e) { 107 LOG.debug(MSG_IOE_WRITE, e); 108 throw new OctaveIOException(MSG_IOE_WRITE, e); 109 } 110 try { 111 this.processWriter.write("\nprintf(\"\\n%s\\n\", \"" + 112 this.spacer + "\");\n"); 113 this.processWriter.flush(); 114 } catch (final IOException e) { 115 LOG.debug(MSG_IOE_SPACER, e); 116 throw new OctaveIOException(MSG_IOE_SPACER, e); 117 } 118 LOG.debug("Has written all"); 119 return null; 120 } 121 122 }