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 }