• R/O
  • SSH

Commit

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

アルファ版。新版→https://osdn.jp/users/tacticsrealize/pf/ChlorophyllUploader/wiki/FrontPage


Commit MetaInfo

Révision2cc40d8f37a47e4a1c86ef6d62685f2a726efab0 (tree)
l'heure2015-06-26 17:39:33
Auteur <15b05@15b0...>

Message de Log

add project

Change Summary

Modification

diff -r 000000000000 -r 2cc40d8f37a4 src/ants/Main.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/Main.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,73 @@
1+package ants;
2+
3+import gnu.io.CommPortIdentifier;
4+import gnu.io.PortInUseException;
5+import gnu.io.RXTXPort;
6+import gnu.io.SerialPort;
7+import gnu.io.UnsupportedCommOperationException;
8+
9+import java.io.PrintStream;
10+
11+import javax.swing.UIManager;
12+import javax.swing.UnsupportedLookAndFeelException;
13+
14+import mirrg.swing.frames.FrameReceiver;
15+import ants.gui.frames.FrameArduino;
16+import ants.gui.frames.FrameSelectPort;
17+
18+public class Main
19+{
20+
21+ public static void init()
22+ {
23+ System.loadLibrary("rxtxSerial");
24+ try {
25+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
26+ } catch (ClassNotFoundException e) {
27+ e.printStackTrace();
28+ } catch (InstantiationException e) {
29+ e.printStackTrace();
30+ } catch (IllegalAccessException e) {
31+ e.printStackTrace();
32+ } catch (UnsupportedLookAndFeelException e) {
33+ e.printStackTrace();
34+ }
35+ }
36+
37+ public static void main(String[] args)
38+ {
39+ init();
40+ new FrameSelectPort(Main::start).setVisible(true);
41+ }
42+
43+ private static void start(CommPortIdentifier portIdentifier)
44+ {
45+ RXTXPort port;
46+ try {
47+ port = (RXTXPort) portIdentifier.open("ANTS_FILE", 2000);
48+ } catch (PortInUseException e) {
49+ e.printStackTrace(new PrintStream(new FrameReceiver().getOut()));
50+ return;
51+ }
52+
53+ try {
54+ port.setSerialPortParams(
55+ 9600,
56+ SerialPort.DATABITS_8,
57+ SerialPort.STOPBITS_1,
58+ SerialPort.PARITY_NONE);
59+ port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
60+ } catch (UnsupportedCommOperationException e) {
61+ FrameReceiver.accept(e);
62+ return;
63+ }
64+
65+ new FrameArduino(
66+ port.getInputStream(),
67+ port.getOutputStream()).setVisible(true);
68+
69+ System.out.println("Start: port=" + portIdentifier.getName());
70+
71+ }
72+
73+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/SampleFileWatcherSpawning.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/SampleFileWatcherSpawning.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,111 @@
1+package ants;
2+
3+import java.io.File;
4+import java.io.FileInputStream;
5+import java.io.InputStreamReader;
6+import java.time.LocalDateTime;
7+import java.time.format.DateTimeFormatter;
8+import java.util.ArrayList;
9+import java.util.List;
10+import java.util.stream.Collectors;
11+import java.util.stream.Stream;
12+
13+import mirrg.file.watcherspawning.FileWatcherSpawning;
14+
15+import com.opencsv.CSVReader;
16+
17+public class SampleFileWatcherSpawning
18+{
19+
20+ /**
21+ * ファイル名
22+ */
23+ private final static DateTimeFormatter formatterIn =
24+ DateTimeFormatter.ofPattern("uuuuMMddHHmmss");
25+
26+ /**
27+ * 保存・Arduino送信形式
28+ */
29+ private final static DateTimeFormatter formatterOut =
30+ DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm:ss");
31+
32+ public static void main(String[] args)
33+ {
34+ FileWatcherSpawning fileWatcherSpawning = new FileWatcherSpawning(
35+ new File("./csvs"),
36+ new File("./config.txt"),
37+ formatterIn,
38+ formatterOut,
39+ (file, localDateTime) -> {
40+ try (CSVReader csvReader = new CSVReader(new InputStreamReader(
41+ new FileInputStream(file)))) {
42+
43+ csvReader.forEach(csvLine ->
44+ SampleFileWatcherSpawning.onData(file, localDateTime, csvLine));
45+ }
46+ });
47+
48+ fileWatcherSpawning.start();
49+
50+ }
51+
52+ private static void onData(File file, LocalDateTime localDateTime, String[] csvLine)
53+ {
54+ // CSV生カットデータがくる
55+
56+ // カットデータの長さチェック
57+ if (csvLine.length != 15) {
58+ System.err.println("illegal size of columns: "
59+ + file
60+ + " (content: ["
61+ + String.join(", ", csvLine)
62+ + "])");
63+ return;
64+ }
65+
66+ // カットデータの整形と型変換
67+ List<Double> doubles;
68+ try {
69+ doubles = Stream.of(csvLine)
70+ .map(String::trim)
71+ .map(Double::parseDouble)
72+ .collect(Collectors.toList());
73+ } catch (NumberFormatException e) {
74+ System.err.println("illegal input string: '"
75+ + e.getMessage()
76+ + "', file: "
77+ + file
78+ + "");
79+ return;
80+ }
81+
82+ // 出力用文字列群のビルド
83+ ArrayList<String> outputs = new ArrayList<>();
84+ outputs.add(formatterOut.format(localDateTime));
85+ doubles.stream()
86+ .map(output -> output.toString())
87+ .forEach(outputs::add);
88+
89+ // 出力用文字列群→出力用1行CSV
90+ String outputCsv = outputs.stream()
91+ .collect(Collectors.joining(","));
92+
93+ // 出力
94+ onData(file, localDateTime, outputCsv);
95+
96+ }
97+
98+ protected static void onData(File file,
99+ LocalDateTime localDateTime,
100+ String outputCsv)
101+ {
102+
103+ System.out.println("Processed!!: '"
104+ + file
105+ + "', "
106+ + localDateTime.format(formatterOut));
107+ System.out.println(outputCsv);
108+
109+ }
110+
111+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/TestFileWatcherDirectory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/TestFileWatcherDirectory.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,122 @@
1+package ants;
2+
3+import java.io.BufferedReader;
4+import java.io.File;
5+import java.io.FileInputStream;
6+import java.io.FileOutputStream;
7+import java.io.IOException;
8+import java.io.InputStreamReader;
9+import java.io.PrintStream;
10+
11+import ants.file.watcherdirectory.FileWatcherDirectory;
12+import ants.file.watcherdirectory.FileWatcherDirectoryListener;
13+
14+public class TestFileWatcherDirectory
15+{
16+
17+ public static void main(String[] args)
18+ {
19+ FileWatcherDirectory fileWatcherDirectory = new FileWatcherDirectory(
20+ new File("run/src"),
21+ new File("run/processing"),
22+ new File("run/dest"),
23+ new File("run/failed"),
24+ new FileWatcherDirectoryListener() {
25+
26+ @Override
27+ public boolean isProcessable(File file)
28+ {
29+ return true;
30+ }
31+
32+ @Override
33+ public boolean process(File file)
34+ {
35+ return processFile(file);
36+ }
37+
38+ });
39+
40+ System.out.println("Start!!");
41+
42+ writeFileDelayed("run/src/test001.txt", "Test!!", 7000, 18000);
43+
44+ fileWatcherDirectory.start();
45+
46+ for (int i = 0; i < 6; i++) {
47+ try {
48+ Thread.sleep(10000);
49+ } catch (InterruptedException e) {
50+ e.printStackTrace();
51+ }
52+ System.out.println("" + i);
53+ }
54+
55+ fileWatcherDirectory.interrupt();
56+
57+ System.out.println("Stop!!");
58+ }
59+
60+ private static void writeFileDelayed(
61+ String filePath, String string, int startMSec, int finishMSec)
62+ {
63+ new Thread(() -> {
64+ try {
65+ Thread.sleep(startMSec);
66+ } catch (Exception e) {
67+ return;
68+ }
69+
70+ File file = new File(filePath);
71+ if (file.exists()) {
72+ System.out.println("exists: " + file);
73+ return;
74+ }
75+
76+ try (FileOutputStream out = new FileOutputStream(file)) {
77+ System.out.println("create: " + file);
78+ PrintStream out2 = new PrintStream(out);
79+
80+ out2.print(string);
81+
82+ try {
83+ Thread.sleep(finishMSec);
84+ } catch (Exception e) {
85+ out2.close();
86+ return;
87+ }
88+
89+ System.out.println("close: " + file);
90+ out2.close();
91+
92+ } catch (IOException e) {
93+ e.printStackTrace();
94+ return;
95+ }
96+ }).start();
97+ }
98+
99+ private static boolean processFile(File file)
100+ {
101+ System.out.println("==" + file + "==");
102+
103+ boolean successed = true;
104+ try {
105+ BufferedReader in =
106+ new BufferedReader(new InputStreamReader(new FileInputStream(file)));
107+
108+ in.lines().forEach(line -> {
109+ System.out.println("> " + line);
110+ });
111+ in.close();
112+
113+ } catch (Exception e) {
114+ e.printStackTrace();
115+ successed = false;
116+ }
117+
118+ System.out.println("==============================");
119+ return successed;
120+ }
121+
122+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/TestFrameAnts.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/TestFrameAnts.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,16 @@
1+package ants;
2+
3+import ants.gui.frames.FrameAnts;
4+
5+public class TestFrameAnts
6+{
7+
8+ public static void main(String[] args)
9+ {
10+ Main.init();
11+
12+ new FrameAnts(System.out::println).setVisible(true);
13+
14+ }
15+
16+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/TestFrameArduino.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/TestFrameArduino.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,34 @@
1+package ants;
2+
3+import java.nio.charset.Charset;
4+
5+import mirrg.swing.frames.FrameReceiver;
6+import mirrg.swing.frames.FrameSender;
7+import ants.gui.frames.FrameArduino;
8+
9+public class TestFrameArduino
10+{
11+
12+ public static void main(String[] args)
13+ {
14+ Main.init();
15+
16+ Charset charset = Charset.forName("UTF-8");
17+
18+ FrameSender frameSender = new FrameSender(charset, false);
19+ frameSender.containerSender.lineSeparator = "\n";
20+ frameSender.setVisible(true);
21+
22+ FrameReceiver frameReceiver = new FrameReceiver(charset);
23+ frameReceiver.setVisible(true);
24+
25+ FrameArduino frameArduino =
26+ new FrameArduino(frameSender.getIn(), frameReceiver.getOut());
27+ frameArduino.setVisible(true);
28+ frameArduino.onClosed(e -> {
29+ frameSender.dispose();
30+ frameReceiver.dispose();
31+ });
32+ }
33+
34+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/TestLocalHTTPServer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/TestLocalHTTPServer.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,41 @@
1+package ants;
2+
3+import java.io.IOException;
4+
5+import ants.http.LocalHTTPServer;
6+
7+public class TestLocalHTTPServer
8+{
9+
10+ /**
11+ * http://127.0.0.1:8080/
12+ */
13+
14+ public static void main(String[] args)
15+ {
16+ LocalHTTPServer localHTTPServer = new LocalHTTPServer(8080, line -> {
17+
18+ System.out.println(line);
19+
20+ });
21+
22+ try {
23+ localHTTPServer.start();
24+ } catch (IOException e1) {
25+ e1.printStackTrace();
26+ return;
27+ }
28+
29+ for (;;) {
30+ try {
31+ Thread.sleep(100);
32+ } catch (InterruptedException e) {
33+ System.out.println("server stop");
34+ break;
35+ }
36+ }
37+
38+ localHTTPServer.stop();
39+ }
40+
41+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/file/watcherdirectory/FileWatcherDirectory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/file/watcherdirectory/FileWatcherDirectory.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,212 @@
1+package ants.file.watcherdirectory;
2+
3+import java.io.File;
4+
5+import mirrg.util.HString;
6+
7+/**
8+ * <p>
9+ * ソース・処理中・処理済・不正ファイルの4つのフォルダを指定し、 {@link #start()}すると、{@link #interrupt()}
10+ * されるまで監視し続ける。{@link #waitMSec}ごとに監視処理が発生し、指定したリスナーにファイルが通知される。
11+ * </p>
12+ * <p>
13+ * ファイルは必ず処理の前に処理中のフォルダに移動する。
14+ * そして、処理が終わったらリスナのメソッドの戻り値によって処理済か不正ファイルのどちらかのフォルダに移動する。
15+ * </p>
16+ * <p>
17+ * どのフォルダに移動するときも、既存のファイルと名前が重複した場合は重複しないように名前を変更する。
18+ * </p>
19+ */
20+public class FileWatcherDirectory extends Thread
21+{
22+
23+ private FileWatcherDirectoryHolder<File> directories = new FileWatcherDirectoryHolder<>();
24+ private FileWatcherDirectoryListener listener;
25+ private FileWatcherDirectoryHolder<String> filePathes = new FileWatcherDirectoryHolder<>();
26+
27+ public volatile int waitMSec = 1000;
28+
29+ /**
30+ * @param predicate
31+ * trueを返すとファイル移動
32+ */
33+ public FileWatcherDirectory(
34+ File directorySrc,
35+ File directoryProcessing,
36+ File directoryDest,
37+ File directoryFailed,
38+ FileWatcherDirectoryListener listener)
39+ {
40+ directories.put(FileWatcherDirectoryHolder.SRC, directorySrc);
41+ directories.put(FileWatcherDirectoryHolder.PROCESSING, directoryProcessing);
42+ directories.put(FileWatcherDirectoryHolder.DEST, directoryDest);
43+ directories.put(FileWatcherDirectoryHolder.FAILED, directoryFailed);
44+ this.listener = listener;
45+ directories.setter(File::getAbsolutePath, filePathes);
46+ }
47+
48+ public void run()
49+ {
50+ // フォルダがちゃんと存在するかチェック
51+ {
52+ directories.forEach((index, directory) -> {
53+ if (!checkDirectory(directory)) {
54+ System.out.println("failed: mkdirs: " + directory);
55+ throw new RuntimeException("failed: mkdirs: " + directory);
56+ }
57+ });
58+ }
59+
60+ directories.forEach((index, directory) -> {
61+ System.out.println("[directory." + index + "] = " + directory);
62+ });
63+
64+ for (;;) {
65+
66+ loop();
67+
68+ try {
69+ Thread.sleep(waitMSec);
70+ } catch (InterruptedException e) {
71+ break;
72+ }
73+ }
74+ }
75+
76+ private void loop()
77+ {
78+ File[] files = directories.src().listFiles();
79+
80+ for (File file : files) {
81+ String filePath = file.getAbsolutePath();
82+ if (filePath.startsWith(filePathes.src())) { // assert
83+ if (file.canRead() && file.canWrite()) {
84+ // !!書き込み中でも通過する
85+ // Windowsのバグらしい
86+ // http://okwave.jp/qa/q3210275.html
87+ // なので一旦移動を試みて移動できてから処理をすることにする
88+
89+ if (listener.isProcessable(file)) {
90+ processFile(file);
91+ }
92+
93+ } else {
94+ System.out.println("! can not read/write: " + file);
95+ }
96+ } else {
97+ System.out.println("! '" + file +
98+ "' is not contains '" + directories.dest() +
99+ "'");
100+ }
101+ }
102+ }
103+
104+ private void processFile(File fileTarget)
105+ {
106+ FileWatcherDirectoryHolder<String> movedFilePathes =
107+ new FileWatcherDirectoryHolder<>();
108+
109+ movedFilePathes.src(fileTarget.getAbsolutePath());
110+
111+ if (!moveFile(movedFilePathes, "src", "processing")) return;
112+
113+ if (listener.process(new File(movedFilePathes.processing()))) {
114+
115+ if (!moveFile(movedFilePathes, "processing", "dest")) return;
116+
117+ System.out.println("succesed: process: " + movedFilePathes.dest());
118+
119+ } else {
120+
121+ if (!moveFile(movedFilePathes, "processing", "failed")) return;
122+
123+ System.out.println("failed: process: " + movedFilePathes.failed());
124+
125+ }
126+
127+ }
128+
129+ /**
130+ * {@link #moveFile(FileWatcherDirectoryHolder, FileWatcherDirectoryHolder, String, String)}
131+ * を呼び出すが、失敗時にエラー文を出す。
132+ */
133+ private boolean moveFile(
134+ FileWatcherDirectoryHolder<String> movedFilePathes,
135+ String src, String dest)
136+ {
137+ if (!moveFile(filePathes, movedFilePathes, src, dest)) {
138+ System.out.println("failed: move:");
139+ System.out.println("> " + movedFilePathes.get(src));
140+ System.out.println("> " + movedFilePathes.get(dest));
141+ return false;
142+ }
143+ //System.out.println("successed: move:");
144+ //System.out.println("> " + movedFilePathes.get(src));
145+ //System.out.println("> " + movedFilePathes.get(dest));
146+ return true;
147+ }
148+
149+ /**
150+ * fileTargetを重複させないように、指定の場所に移動させる。
151+ * 実際の場所をmovedFilePathesから取得し、実際の移動先をmovedFilePathesに格納する。
152+ * movedFilePathesの"src"に何かが入っていないといけない。
153+ */
154+ private static boolean moveFile(
155+ FileWatcherDirectoryHolder<String> filePathes,
156+ FileWatcherDirectoryHolder<String> movedFilePathes,
157+ String src,
158+ String dest)
159+ {
160+ movedFilePathes.put(dest, getMovedFilePath(
161+ filePathes.get("src"),
162+ filePathes.get(dest),
163+ movedFilePathes.get("src")));
164+
165+ if (!new File(movedFilePathes.get(src)).renameTo(
166+ new File(movedFilePathes.get(dest)))) {
167+ return false;
168+ }
169+
170+ return true;
171+ }
172+
173+ /**
174+ * ディレクトリーがなければ作る。
175+ * 作れなかったらfalse。
176+ */
177+ private static boolean checkDirectory(File directory)
178+ {
179+ if (!directory.exists()) {
180+ if (directory.mkdirs()) {
181+ System.out.println("mkdirs: " + directory);
182+ } else {
183+ return false;
184+ }
185+ }
186+ return true;
187+ }
188+
189+ /**
190+ * filePathのうち、srcFilePathと一致する部分をdestFilePathに置換した場所に移動させる。
191+ * 適当にファイル名が重複しないように名前変更してファイルを移動させる。
192+ */
193+ private static String getMovedFilePath(
194+ String srcFilePath, String destFilePath, String filePath)
195+ {
196+ String movedFilePath2 = filePath.replace(srcFilePath, destFilePath);
197+ int index = 0;
198+
199+ for (;;) {
200+ String movedFilePath = HString.getIndexedFilePath(movedFilePath2, index);
201+ File file = new File(movedFilePath);
202+
203+ if (file.exists()) {
204+ index++;
205+ } else {
206+ return movedFilePath;
207+ }
208+ }
209+
210+ }
211+
212+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/file/watcherdirectory/FileWatcherDirectoryHolder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/file/watcherdirectory/FileWatcherDirectoryHolder.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,90 @@
1+package ants.file.watcherdirectory;
2+
3+import java.util.Hashtable;
4+import java.util.function.BiFunction;
5+import java.util.function.Function;
6+
7+public class FileWatcherDirectoryHolder<T> extends Hashtable<String, T>
8+{
9+
10+ public static final String SRC = "src";
11+ public static final String PROCESSING = "processing";
12+ public static final String DEST = "dest";
13+ public static final String FAILED = "failed";
14+
15+ public static String[] keys = {
16+ SRC,
17+ PROCESSING,
18+ DEST,
19+ FAILED,
20+ };
21+
22+ public T src()
23+ {
24+ return get(SRC);
25+ }
26+
27+ public T processing()
28+ {
29+ return get(PROCESSING);
30+ }
31+
32+ public T dest()
33+ {
34+ return get(DEST);
35+ }
36+
37+ public T failed()
38+ {
39+ return get(FAILED);
40+ }
41+
42+ public void src(T value)
43+ {
44+ put(SRC, value);
45+ }
46+
47+ public void processing(T value)
48+ {
49+ put(PROCESSING, value);
50+ }
51+
52+ public void dest(T value)
53+ {
54+ put(DEST, value);
55+ }
56+
57+ public void failed(T value)
58+ {
59+ put(FAILED, value);
60+ }
61+
62+ public <U> void setter(Function<? super T, ? extends U> function, FileWatcherDirectoryHolder<U> dest)
63+ {
64+ forEach((index, item) -> {
65+ dest.put(index, function.apply(item));
66+ });
67+ }
68+
69+ public <U> void setter(BiFunction<String, ? super T, ? extends U> function, FileWatcherDirectoryHolder<U> dest)
70+ {
71+ forEach((index, item) -> {
72+ dest.put(index, function.apply(index, item));
73+ });
74+ }
75+
76+ public <U> FileWatcherDirectoryHolder<U> createHolder(Function<? super T, ? extends U> function)
77+ {
78+ FileWatcherDirectoryHolder<U> dest = new FileWatcherDirectoryHolder<>();
79+ setter(function, dest);
80+ return dest;
81+ }
82+
83+ public <U> FileWatcherDirectoryHolder<U> createHolder(BiFunction<String, ? super T, ? extends U> function)
84+ {
85+ FileWatcherDirectoryHolder<U> dest = new FileWatcherDirectoryHolder<>();
86+ setter(function, dest);
87+ return dest;
88+ }
89+
90+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/file/watcherdirectory/FileWatcherDirectoryListener.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/file/watcherdirectory/FileWatcherDirectoryListener.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,12 @@
1+package ants.file.watcherdirectory;
2+
3+import java.io.File;
4+
5+public interface FileWatcherDirectoryListener
6+{
7+
8+ public boolean isProcessable(File file);
9+
10+ public boolean process(File file);
11+
12+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/gui/frames/FrameAnts.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/gui/frames/FrameAnts.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,218 @@
1+package ants.gui.frames;
2+
3+import java.awt.Component;
4+import java.awt.Dimension;
5+import java.text.SimpleDateFormat;
6+import java.time.LocalDateTime;
7+import java.time.ZoneId;
8+import java.time.format.DateTimeFormatter;
9+import java.time.temporal.ChronoField;
10+import java.util.Date;
11+import java.util.function.Consumer;
12+
13+import javax.swing.JButton;
14+import javax.swing.JCheckBox;
15+import javax.swing.JLabel;
16+import javax.swing.JScrollPane;
17+import javax.swing.JSpinner;
18+import javax.swing.JTextArea;
19+import javax.swing.SpinnerDateModel;
20+import javax.swing.SpinnerNumberModel;
21+import javax.swing.Timer;
22+
23+import jp.hishidama.swing.layout.GroupLayoutUtil;
24+import mirrg.util.FrameMirrg;
25+import mirrg.util.HFrame;
26+import mirrg.util.HString;
27+import mirrg.util.Tuple;
28+
29+public class FrameAnts extends FrameMirrg
30+{
31+
32+ private static final String dateFormat = "yyyy/MM/dd/HH:mm:ss";
33+ private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
34+ private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(dateFormat);
35+
36+ private Consumer<String> consumer;
37+
38+ private JCheckBox checkBox1;
39+ private JCheckBox checkBox2;
40+ private Tuple<JLabel, JSpinner> spinnerRow1;
41+ private Tuple<JLabel, JSpinner> spinnerRow2;
42+ private Tuple<JLabel, JSpinner> spinnerRow3;
43+ private Tuple<JLabel, JSpinner> spinnerRow4;
44+ private Tuple<JLabel, JSpinner> spinnerRow5;
45+ private Tuple<JLabel, JSpinner> spinnerRow6;
46+ private Tuple<JLabel, JSpinner> spinnerRow7;
47+ private Tuple<JLabel, JSpinner> spinnerRow8;
48+ private JTextArea textArea1;
49+
50+ public FrameAnts(Consumer<String> consumer)
51+ {
52+ super("ANTS");
53+
54+ this.consumer = consumer;
55+
56+ buildForm();
57+
58+ prepareFrame();
59+
60+ refresh();
61+ }
62+
63+ private static Tuple<JLabel, JSpinner> createSpinnerRowDate(String labelText)
64+ {
65+ JLabel label = new JLabel(labelText);
66+
67+ JSpinner spinner = new JSpinner(new SpinnerDateModel());
68+ spinner.setEditor(new JSpinner.DateEditor(spinner, dateFormat));
69+
70+ return new Tuple<>(label, spinner);
71+ }
72+
73+ private static Tuple<JLabel, JSpinner> createSpinnerRowDouble(
74+ String labelText, double value, double min, double max, double step)
75+ {
76+ JLabel label = new JLabel(labelText);
77+
78+ JSpinner spinner = new JSpinner(new SpinnerNumberModel(value, min, max, step));
79+ spinner.setEditor(new JSpinner.NumberEditor(spinner));
80+
81+ return new Tuple<>(label, spinner);
82+ }
83+
84+ private Tuple<JLabel, JSpinner> refresher(Tuple<JLabel, JSpinner> spinnerRow)
85+ {
86+ spinnerRow.getY().addChangeListener(e -> {
87+ refresh();
88+ });
89+ return spinnerRow;
90+ }
91+
92+ private void refresh()
93+ {
94+ textArea1.setText(makeScript());
95+ }
96+
97+ //15/4/24/19:28:0/2,T:99.87,H:30.45,VPD:1.83,CO2:1107,SW:50,Power:80,ETIME:65
98+
99+ private String makeScript()
100+ {
101+ Date date = (Date) spinnerRow1.getY().getValue();
102+ String dateString = simpleDateFormat.format(date);
103+ LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateFormatter);
104+
105+ return String.format(
106+ "%s/%s,T:%s,H:%s,VPD:%s,CO2:%s,SW:%s,Power:%s,ETIME:%s",
107+ dateString,
108+ localDateTime.get(ChronoField.DAY_OF_WEEK) % 7,
109+ HString.toString((double) spinnerRow2.getY().getValue()),
110+ HString.toString((double) spinnerRow3.getY().getValue()),
111+ HString.toString((double) spinnerRow4.getY().getValue()),
112+ (int) (double) spinnerRow5.getY().getValue(),
113+ (int) (double) spinnerRow6.getY().getValue(),
114+ HString.toString((double) spinnerRow7.getY().getValue()),
115+ HString.toString((double) spinnerRow8.getY().getValue()));
116+ }
117+
118+ protected void buildForm()
119+ {
120+
121+ checkBox1 = new JCheckBox("現在時刻", true);
122+ checkBox2 = new JCheckBox("秒を0に固定", false);
123+
124+ spinnerRow1 = createSpinnerRowDate("日付時刻");
125+ spinnerRow2 = createSpinnerRowDouble("温度", 25, -50, 100, 0.1);
126+ spinnerRow3 = createSpinnerRowDouble("湿度", 50, 0, 100, 0.5);
127+ spinnerRow4 = createSpinnerRowDouble("VPD", 1.8, -10000, 10000, 0.1);
128+ spinnerRow5 = createSpinnerRowDouble("CO2(int)", 1100, -10000, 10000, 1);
129+ spinnerRow6 = createSpinnerRowDouble("SW(int)", 50, -10000, 10000, 1);
130+ spinnerRow7 = createSpinnerRowDouble("Power", 80, -10000, 10000, 1);
131+ spinnerRow8 = createSpinnerRowDouble("ETIME", 65, -10000, 10000, 1);
132+
133+ refresher(spinnerRow1);
134+ refresher(spinnerRow2);
135+ refresher(spinnerRow3);
136+ refresher(spinnerRow4);
137+ refresher(spinnerRow5);
138+ refresher(spinnerRow6);
139+ refresher(spinnerRow7);
140+ refresher(spinnerRow8);
141+
142+ {
143+ Timer timer1 = new Timer(1000, e -> {
144+ if (!checkBox1.isSelected()) return;
145+
146+ LocalDateTime value = LocalDateTime.now();
147+ if (checkBox2.isSelected()) {
148+ value = value.minusSeconds(value.getSecond());
149+ }
150+ spinnerRow1.getY().getModel().setValue(
151+ Date.from(
152+ value.atZone(ZoneId.systemDefault()).toInstant()));
153+ });
154+ timer1.start();
155+
156+ onClosed(e -> {
157+ timer1.stop();
158+ });
159+ }
160+
161+ JButton button1 = new JButton("送信");
162+ button1.addActionListener(e -> {
163+ consumer.accept(textArea1.getText());
164+ });
165+
166+ textArea1 = new JTextArea();
167+ textArea1.setLineWrap(true);
168+ JScrollPane scrollPane1 = new JScrollPane(textArea1);
169+ scrollPane1.setPreferredSize(new Dimension(100, 100));
170+ textArea1.setFont(HFrame.getEditableMonospaceFont());
171+
172+ {
173+ Component[][] compos = {
174+ {
175+ checkBox1, checkBox2,
176+ },
177+ {
178+ spinnerRow1.getX(), spinnerRow1.getY(),
179+ },
180+ {
181+ spinnerRow2.getX(), spinnerRow2.getY(),
182+ },
183+ {
184+ spinnerRow3.getX(), spinnerRow3.getY(),
185+ },
186+ {
187+ spinnerRow4.getX(), spinnerRow4.getY(),
188+ },
189+ {
190+ spinnerRow5.getX(), spinnerRow5.getY(),
191+ },
192+ {
193+ spinnerRow6.getX(), spinnerRow6.getY(),
194+ },
195+ {
196+ spinnerRow7.getX(), spinnerRow7.getY(),
197+ },
198+ {
199+ spinnerRow8.getX(), spinnerRow8.getY(),
200+ },
201+ {
202+ scrollPane1, GroupLayoutUtil.SAME_L,
203+ },
204+ {
205+ button1, GroupLayoutUtil.SAME_L,
206+ },
207+ };
208+
209+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
210+
211+ groupLayoutUtil.setComponents(compos);
212+ groupLayoutUtil.setGroupLayoutTo(this.getContentPane());
213+
214+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(true);
215+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
216+ }
217+ }
218+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/gui/frames/FrameArduino.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/gui/frames/FrameArduino.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,147 @@
1+package ants.gui.frames;
2+
3+import java.awt.Component;
4+import java.awt.FlowLayout;
5+import java.io.IOException;
6+import java.io.InputStream;
7+import java.io.OutputStream;
8+import java.io.PrintStream;
9+import java.nio.charset.Charset;
10+
11+import javax.swing.BorderFactory;
12+import javax.swing.JButton;
13+import javax.swing.JComponent;
14+import javax.swing.JFrame;
15+
16+import jp.hishidama.swing.layout.GroupLayoutUtil;
17+import mirrg.swing.components.ContainerSenderAndReceiver;
18+import mirrg.swing.frames.FrameReceiver;
19+import mirrg.util.FrameMirrg;
20+import mirrg.util.UTF8StreamReader;
21+
22+/**
23+ * 入力時にバッファリングを全部手動でやる
24+ * →改行文字を手動で判別
25+ * →UTF-8しか対応してない
26+ */
27+public class FrameArduino extends FrameMirrg
28+{
29+
30+ private ContainerSenderAndReceiver containerSenderAndReceiver;
31+
32+ public FrameArduino(InputStream inputStream, OutputStream outputStream)
33+ {
34+ super("Arduino");
35+
36+ Charset charset = Charset.forName("UTF-8");
37+
38+ onClosed(e -> {
39+ try {
40+ inputStream.close();
41+ } catch (IOException e2) {
42+ FrameReceiver.accept(e2);
43+ }
44+ try {
45+ outputStream.close();
46+ } catch (IOException e2) {
47+ FrameReceiver.accept(e2);
48+ }
49+ });
50+
51+ buildForm(inputStream, outputStream, charset);
52+
53+ prepareFrame();
54+ }
55+
56+ private void buildForm(InputStream inputStream, OutputStream outputStream, Charset charset)
57+ {
58+ JFrame frame = this;
59+ {
60+
61+ JComponent containerButtons = new JComponent() {
62+ };
63+ {
64+ FlowLayout flowLayout = new FlowLayout();
65+ flowLayout.setAlignment(FlowLayout.LEFT);
66+ containerButtons.setLayout(flowLayout);
67+ }
68+ containerButtons.setBorder(BorderFactory.createTitledBorder("機能"));
69+ {
70+
71+ JButton button1 = new JButton("入力フォーム");
72+ button1.addActionListener(e -> {
73+ FrameAnts frameAnts = new FrameAnts(text -> {
74+ containerSenderAndReceiver.getContainerSender().println(text);
75+ });
76+ frameAnts.setVisible(true);
77+ onClosed(e2 -> {
78+ frameAnts.dispose();
79+ });
80+ });
81+ containerButtons.add(button1);
82+
83+ }
84+
85+ containerSenderAndReceiver = new ContainerSenderAndReceiver(charset);
86+
87+ //
88+
89+ Thread thread1 = new Thread(() -> {
90+ PrintStream printStream;
91+ try {
92+ printStream = new PrintStream(
93+ containerSenderAndReceiver.getContainerReceiver().getOut(), true, charset.name());
94+ } catch (Exception e) {
95+ throw new RuntimeException(e);
96+ }
97+ new UTF8StreamReader(inputStream, false).stream(line -> {
98+ //System.out.println("++++" + line); // TODO
99+ printStream.println(line);
100+ });
101+ });
102+ thread1.setDaemon(true);
103+ thread1.start();
104+ onClosed(e -> {
105+ thread1.interrupt();
106+ });
107+
108+ containerSenderAndReceiver.getContainerSender().lineSeparator = "\n";
109+ Thread thread2 = new Thread(() -> {
110+ PrintStream printStream;
111+ try {
112+ printStream = new PrintStream(outputStream, true, charset.name());
113+ } catch (Exception e) {
114+ throw new RuntimeException(e);
115+ }
116+ new UTF8StreamReader(containerSenderAndReceiver.getContainerSender().getIn(), false).stream(line -> {
117+ //System.out.println("----" + line); // TODO
118+ printStream.println(line);
119+ });
120+ });
121+ thread2.setDaemon(true);
122+ thread2.start();
123+ onClosed(e -> {
124+ thread2.interrupt();
125+ });
126+
127+ {
128+ Component[][] compos = {
129+ {
130+ containerButtons,
131+ }, {
132+ containerSenderAndReceiver,
133+ },
134+ };
135+
136+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
137+
138+ groupLayoutUtil.setComponents(compos);
139+ groupLayoutUtil.setGroupLayoutTo(frame.getContentPane());
140+
141+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(true);
142+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
143+ }
144+ }
145+ }
146+
147+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/gui/frames/FrameSelectPort.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/gui/frames/FrameSelectPort.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,157 @@
1+package ants.gui.frames;
2+
3+import gnu.io.CommPortIdentifier;
4+
5+import java.awt.Component;
6+import java.awt.event.MouseEvent;
7+import java.awt.event.MouseListener;
8+import java.util.Enumeration;
9+import java.util.Vector;
10+import java.util.function.Consumer;
11+
12+import javax.swing.JButton;
13+import javax.swing.JFrame;
14+import javax.swing.JList;
15+import javax.swing.JScrollPane;
16+
17+import jp.hishidama.swing.layout.GroupLayoutUtil;
18+import mirrg.util.FrameMirrg;
19+
20+public class FrameSelectPort extends FrameMirrg
21+{
22+
23+ private JList<Wrapper<CommPortIdentifier>> list;
24+ private Consumer<CommPortIdentifier> consumer;
25+
26+ public FrameSelectPort(Consumer<CommPortIdentifier> consumer)
27+ {
28+ super("ポート選択");
29+
30+ this.consumer = consumer;
31+
32+ JFrame frame = this;
33+ {
34+
35+ list = new JList<>();
36+ list.addMouseListener(new MouseListener() {
37+
38+ @Override
39+ public void mouseClicked(MouseEvent e)
40+ {
41+ if (e.getClickCount() == 2) {
42+ send();
43+ }
44+ }
45+
46+ @Override
47+ public void mousePressed(MouseEvent e)
48+ {
49+
50+ }
51+
52+ @Override
53+ public void mouseReleased(MouseEvent e)
54+ {
55+
56+ }
57+
58+ @Override
59+ public void mouseEntered(MouseEvent e)
60+ {
61+
62+ }
63+
64+ @Override
65+ public void mouseExited(MouseEvent e)
66+ {
67+
68+ }
69+ });
70+ JScrollPane scrollPane = new JScrollPane(list);
71+
72+ JButton button1 = new JButton("再読み込み");
73+ button1.addActionListener(e -> {
74+ redraw(list);
75+ });
76+
77+ JButton button2 = new JButton("OK");
78+ button2.addActionListener(e -> {
79+ send();
80+ });
81+
82+ {
83+ Component[][] compos = {
84+ {
85+ scrollPane, GroupLayoutUtil.SAME_L
86+ },
87+ {
88+ button1, button2,
89+ },
90+ };
91+
92+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
93+
94+ groupLayoutUtil.setComponents(compos);
95+ groupLayoutUtil.setGroupLayoutTo(frame.getContentPane());
96+
97+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(true);
98+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
99+ }
100+ }
101+
102+ redraw(list);
103+
104+ prepareFrame();
105+ }
106+
107+ private void send()
108+ {
109+ Wrapper<CommPortIdentifier> portIdentifier = list.getSelectedValue();
110+ if (portIdentifier != null) {
111+ if (portIdentifier.x != null) {
112+ dispose();
113+ consumer.accept(portIdentifier.x);
114+ }
115+ }
116+ }
117+
118+ public static class Wrapper<X>
119+ {
120+
121+ public X x;
122+ public String name;
123+
124+ public Wrapper(X x, String name)
125+ {
126+ this.x = x;
127+ this.name = name;
128+ }
129+
130+ @Override
131+ public String toString()
132+ {
133+ return name;
134+ }
135+
136+ }
137+
138+ private static void redraw(JList<Wrapper<CommPortIdentifier>> list)
139+ {
140+ Enumeration<CommPortIdentifier> portIdentifiers = getPortIdentifiers();
141+
142+ Vector<Wrapper<CommPortIdentifier>> vector = new Vector<>();
143+ while (portIdentifiers.hasMoreElements()) {
144+ CommPortIdentifier portIdentifier = portIdentifiers.nextElement();
145+ vector.add(new Wrapper<>(portIdentifier, portIdentifier.getName()));
146+ }
147+
148+ list.setListData(vector);
149+ }
150+
151+ @SuppressWarnings("unchecked")
152+ private static Enumeration<CommPortIdentifier> getPortIdentifiers()
153+ {
154+ return (Enumeration<CommPortIdentifier>) CommPortIdentifier.getPortIdentifiers();
155+ }
156+
157+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/http/LocalHTTPServer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/http/LocalHTTPServer.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,46 @@
1+package ants.http;
2+
3+import java.io.InputStream;
4+import java.util.Map;
5+import java.util.function.Consumer;
6+
7+import fi.iki.elonen.NanoHTTPD;
8+import fi.iki.elonen.NanoHTTPD.Response.Status;
9+
10+public class LocalHTTPServer extends NanoHTTPD
11+{
12+
13+ private Consumer<String> listener;
14+
15+ public LocalHTTPServer(int port, Consumer<String> listener)
16+ {
17+ super("127.0.0.1", port);
18+ this.listener = listener;
19+ }
20+
21+ @Override
22+ public Response serve(IHTTPSession session)
23+ {
24+ String uri = session.getUri();
25+ Method method = session.getMethod();
26+ Map<String, String> parameters = session.getParms();
27+
28+ if (method == Method.GET && uri.equals("/send")) {
29+
30+ listener.accept(parameters.get("query"));
31+
32+ Response response = new Response(Status.REDIRECT, "text/plain", "");
33+ response.addHeader("Location", "/xs");
34+ return response;
35+ }
36+
37+ return new Response(Status.OK, "text/html",
38+ getIndexHtml());
39+ }
40+
41+ private InputStream getIndexHtml()
42+ {
43+ return getClass().getResourceAsStream("index.html");
44+ }
45+
46+}
diff -r 000000000000 -r 2cc40d8f37a4 src/ants/http/index.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ants/http/index.html Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,13 @@
1+<!DOCTYPE html>
2+<html>
3+<head>
4+<meta charset="UTF-8">
5+</head>
6+<body>
7+ <a href="/">Top</a>
8+ <form method="get" action="/send">
9+ Query:
10+ <textarea style="width: 200px; height: 200px;" name="query"></textarea>
11+ <br> <input type="submit" value="Post">
12+ </form>
13+</body>
\ No newline at end of file
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/file/watcherspawning/FileWatcherSpawning.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/file/watcherspawning/FileWatcherSpawning.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,209 @@
1+package mirrg.file.watcherspawning;
2+
3+import java.io.BufferedReader;
4+import java.io.File;
5+import java.io.FileInputStream;
6+import java.io.FileNotFoundException;
7+import java.io.FileOutputStream;
8+import java.io.IOException;
9+import java.io.InputStreamReader;
10+import java.io.PrintStream;
11+import java.time.LocalDateTime;
12+import java.time.format.DateTimeFormatter;
13+import java.time.format.DateTimeParseException;
14+import java.util.HashSet;
15+import java.util.stream.Collectors;
16+import java.util.stream.Stream;
17+
18+import mirrg.util.HString;
19+import mirrg.util.Tuple;
20+
21+/**
22+ * {@link #directory}の内部を監視して、以下の条件のファイルに対して処理を行う。
23+ * <ul>
24+ * <li>直下のディレクトリに存在する。
25+ * <li>ファイル名が、「{@link #formatterIn} + "." + 任意の拡張子」である。
26+ * <li>処理済のファイルではない。
27+ * </ul>
28+ * <p>
29+ * 処理済みかどうかは、{@link #fileConfig}の内容と比較する。 この内容は、{@link #formatterOut}の形式で保存される。
30+ * 処理を行った場合このファイルの内容が更新されていくため、 同じディレクトリに次々と新しいファイルを投入することができる。
31+ * </p>
32+ * <p>
33+ * {@link #listener}は、ファイルの処理を行うためのリスナである。 ファイル・ファイルの内容・ファイル名に含まれる日付データが渡される。
34+ * このイベントリスナ内で例外が発生した場合、 そのファイルを未処理扱いとして{@link #fileConfig}を更新せずにアプリケーションごと終了する。
35+ * </p>
36+ */
37+public class FileWatcherSpawning extends Thread
38+{
39+
40+ /**
41+ * 監視イベントが発生する周期
42+ */
43+ public volatile int waitMs = 10000;
44+
45+ protected File directory;
46+ protected File fileConfig;
47+ protected DateTimeFormatter formatterIn;
48+ protected DateTimeFormatter formatterOut;
49+ protected IListenerFileWatcherSpawning listener;
50+
51+ /**
52+ * 軽量化用キャッシュ
53+ */
54+ protected HashSet<File> processed = new HashSet<>();
55+
56+ public FileWatcherSpawning(
57+ File directory,
58+ File fileConfig,
59+ DateTimeFormatter formatterIn,
60+ DateTimeFormatter formatterOut,
61+ IListenerFileWatcherSpawning listener)
62+ {
63+ this.directory = directory;
64+ this.fileConfig = fileConfig;
65+ this.formatterIn = formatterIn;
66+ this.formatterOut = formatterOut;
67+ this.listener = listener;
68+ }
69+
70+ @Override
71+ public void run()
72+ {
73+ if (!directory.exists()) {
74+ throw new RuntimeException(new FileNotFoundException(directory.toString()));
75+ }
76+
77+ System.out.println("start watching (wait [ms]: "
78+ + waitMs
79+ + "): "
80+ + directory
81+ + "");
82+
83+ while (true) {
84+ try {
85+ Thread.sleep(waitMs);
86+ } catch (InterruptedException e) {
87+ break;
88+ }
89+
90+ checkUpdate();
91+
92+ }
93+
94+ }
95+
96+ public static String readFile(File file) throws IOException
97+ {
98+ if (!file.exists()) {
99+ file.createNewFile();
100+ }
101+
102+ BufferedReader in = new BufferedReader(
103+ new InputStreamReader(new FileInputStream(file)));
104+
105+ String content = in.lines().collect(Collectors.joining("\n"));
106+ in.close();
107+
108+ return content;
109+ }
110+
111+ protected static void writeFile(File file, String content) throws FileNotFoundException
112+ {
113+ PrintStream out = new PrintStream(new FileOutputStream(file));
114+
115+ out.print(content);
116+ out.close();
117+
118+ }
119+
120+ protected LocalDateTime getRecentProcessFileEntry()
121+ {
122+ try {
123+ String string = readFile(fileConfig);
124+
125+ try {
126+ LocalDateTime localDateTime = LocalDateTime.parse(string, formatterOut);
127+ return localDateTime;
128+ } catch (DateTimeParseException e) {
129+ return LocalDateTime.MIN;
130+ }
131+ } catch (IOException e) {
132+ throw new RuntimeException(e);
133+ }
134+ }
135+
136+ protected void setRecentProcessFileEntry(LocalDateTime localDateTime)
137+ {
138+ try {
139+ String content = formatterOut.format(localDateTime);
140+ writeFile(fileConfig, content);
141+ } catch (FileNotFoundException e) {
142+ throw new RuntimeException(e);
143+ }
144+ }
145+
146+ protected void checkUpdate()
147+ {
148+ File[] files = directory.listFiles();
149+ LocalDateTime[] recentProcessFileEntry = {
150+ getRecentProcessFileEntry(),
151+ };
152+
153+ Stream.of(files)
154+ .sequential()
155+ .filter(file -> {
156+ boolean ok = !processed.contains(file);
157+ if (ok) processed.add(file);
158+ return ok;
159+ })
160+ .map(file -> new Tuple<File, String>(file, file.getName()))
161+ .map(tuple -> new Tuple<File, String>(
162+ tuple.getX(),
163+ HString.deleteExtension(tuple.getY())))
164+ .map(tuple -> {
165+ try {
166+ return new Tuple<File, LocalDateTime>(
167+ tuple.getX(),
168+ LocalDateTime.parse(tuple.getY(), formatterIn));
169+ } catch (DateTimeParseException e) {
170+
171+ System.err.println("illegal file name: "
172+ + tuple.getY()
173+ + " (format example: '"
174+ + formatterIn.format(LocalDateTime.now())
175+ + "', error index: "
176+ + e.getErrorIndex()
177+ + ")");
178+ return null;
179+ }
180+ })
181+ .filter(a -> a != null)
182+ .sorted((a, b) -> a.getY().compareTo(b.getY()))
183+ .filter(tuple ->
184+ tuple.getY().compareTo(recentProcessFileEntry[0]) > 0)
185+ .forEach(tuple -> {
186+
187+ processFile(tuple);
188+
189+ recentProcessFileEntry[0] = tuple.getY();
190+ setRecentProcessFileEntry(recentProcessFileEntry[0]);
191+ });
192+
193+ }
194+
195+ protected void processFile(Tuple<File, LocalDateTime> tuple)
196+ {
197+ try {
198+
199+ listener.process(
200+ tuple.getX(),
201+ tuple.getY());
202+
203+ } catch (IOException e) {
204+ System.err.println("could not open this file: " + tuple);
205+ e.printStackTrace(System.err);
206+ }
207+ }
208+
209+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/file/watcherspawning/IListenerFileWatcherSpawning.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/file/watcherspawning/IListenerFileWatcherSpawning.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,12 @@
1+package mirrg.file.watcherspawning;
2+
3+import java.io.File;
4+import java.io.IOException;
5+import java.time.LocalDateTime;
6+
7+public interface IListenerFileWatcherSpawning
8+{
9+
10+ public void process(File file, LocalDateTime localDateTime) throws IOException;
11+
12+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/swing/components/ContainerReceiver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/swing/components/ContainerReceiver.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,120 @@
1+package mirrg.swing.components;
2+
3+import java.awt.Component;
4+import java.awt.Dimension;
5+import java.io.IOException;
6+import java.io.OutputStream;
7+import java.nio.charset.Charset;
8+import java.util.ArrayList;
9+
10+import javax.swing.JCheckBox;
11+import javax.swing.JComponent;
12+import javax.swing.JScrollBar;
13+import javax.swing.JScrollPane;
14+import javax.swing.JTextArea;
15+import javax.swing.SwingUtilities;
16+
17+import jp.hishidama.swing.layout.GroupLayoutUtil;
18+import mirrg.util.HFrame;
19+
20+public class ContainerReceiver extends JComponent
21+{
22+
23+ public OutputStream out;
24+
25+ private JCheckBox checkBox1;
26+ private JTextArea textArea;
27+ private JScrollPane scrollPane1;
28+
29+ public ContainerReceiver(Charset charset)
30+ {
31+
32+ buildForm();
33+
34+ out = new OutputStream() {
35+ private ArrayList<Byte> buffer = new ArrayList<>();
36+
37+ @Override
38+ public void write(int b) throws IOException
39+ {
40+ buffer.add((byte) b);
41+ if (b == 13) {
42+ flush();
43+ }
44+ }
45+
46+ @Override
47+ public synchronized void flush() throws IOException
48+ {
49+ byte[] buffer2 = new byte[buffer.size()];
50+ for (int i = 0; i < buffer2.length; i++) {
51+ buffer2[i] = buffer.get(i);
52+ }
53+ buffer.clear();
54+ print(new String(buffer2, charset));
55+ }
56+
57+ };
58+ }
59+
60+ private void buildForm()
61+ {
62+
63+ checkBox1 = new JCheckBox("自動スクロール");
64+
65+ textArea = new JTextArea();
66+ scrollPane1 = new JScrollPane(textArea);
67+ scrollPane1.setPreferredSize(new Dimension(300, 300));
68+ textArea.setFont(HFrame.getEditableMonospaceFont());
69+ textArea.setEditable(false);
70+
71+ {
72+ Component[][] compos = {
73+ {
74+ checkBox1,
75+ },
76+ {
77+ scrollPane1,
78+ },
79+ };
80+
81+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
82+
83+ groupLayoutUtil.setComponents(compos);
84+ groupLayoutUtil.setGroupLayoutTo(this);
85+
86+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(false);
87+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
88+ }
89+ }
90+
91+ public String getText()
92+ {
93+ return textArea.getText();
94+ }
95+
96+ public void setText(String text)
97+ {
98+ textArea.setText(text);
99+ }
100+
101+ public void print(String string)
102+ {
103+ SwingUtilities.invokeLater(() -> {
104+ textArea.setText(textArea.getText() + string);
105+
106+ if (checkBox1.isSelected()) {
107+ JScrollBar verticalScrollBar = scrollPane1.getVerticalScrollBar();
108+ verticalScrollBar.setValue(
109+ verticalScrollBar.getMaximum()
110+ - verticalScrollBar.getVisibleAmount());
111+ }
112+ });
113+ }
114+
115+ public OutputStream getOut()
116+ {
117+ return out;
118+ }
119+
120+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/swing/components/ContainerSender.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/swing/components/ContainerSender.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,155 @@
1+package mirrg.swing.components;
2+
3+import java.awt.Component;
4+import java.io.IOException;
5+import java.io.InputStream;
6+import java.nio.charset.Charset;
7+import java.util.ArrayList;
8+
9+import javax.swing.JButton;
10+import javax.swing.JComponent;
11+import javax.swing.JTextField;
12+import javax.swing.SwingUtilities;
13+
14+import jp.hishidama.swing.layout.GroupLayoutUtil;
15+import mirrg.util.HFrame;
16+
17+public class ContainerSender extends JComponent
18+{
19+
20+ public InputStream in;
21+
22+ private JTextField textField;
23+
24+ private Charset charset;
25+
26+ private ArrayList<Byte> buffer = new ArrayList<>();
27+ private int seek = 0;
28+ private boolean closed = false;
29+
30+ public String lineSeparator = System.lineSeparator();
31+
32+ public ContainerSender(Charset charset, boolean blocking)
33+ {
34+ this.charset = charset;
35+
36+ buildForm();
37+
38+ in = new InputStream() {
39+ @Override
40+ public int available() throws IOException
41+ {
42+ return buffer.size() - seek;
43+ }
44+
45+ @Override
46+ public int read() throws IOException
47+ {
48+ while (!closed) {
49+
50+ int b = ContainerSender.this.read();
51+ if (b >= 0) {
52+ return b;
53+ }
54+
55+ if (blocking) {
56+ return -1;
57+ }
58+
59+ try {
60+ Thread.sleep(1);
61+ } catch (InterruptedException e) {
62+ break;
63+ }
64+ }
65+ return -1;
66+ }
67+ };
68+ }
69+
70+ private void buildForm()
71+ {
72+
73+ textField = new JTextField();
74+ textField.addActionListener(e -> {
75+ SwingUtilities.invokeLater(() -> {
76+ if (textField.getText().length() > 0) {
77+ println(textField.getText());
78+ textField.setText("");
79+ }
80+ });
81+ });
82+ textField.setFont(HFrame.getEditableMonospaceFont());
83+
84+ JButton button1 = new JButton("送信");
85+ button1.addActionListener(e -> {
86+ if (textField.getText().length() > 0) {
87+ println(textField.getText());
88+ textField.setText("");
89+ }
90+ });
91+
92+ JButton button2 = new JButton("ストリームを閉じる");
93+ button2.addActionListener(e -> {
94+ if (textField.getText().length() > 0) {
95+ close();
96+ }
97+ });
98+
99+ {
100+ Component[][] compos = {
101+ {
102+ textField, button1,
103+ },
104+ {
105+ button2, null,
106+ },
107+ };
108+
109+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
110+
111+ groupLayoutUtil.setComponents(compos);
112+ groupLayoutUtil.setGroupLayoutTo(this);
113+
114+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(false);
115+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
116+ }
117+ }
118+
119+ public void close()
120+ {
121+ closed = true;
122+ }
123+
124+ private synchronized int read()
125+ {
126+ //System.out.println("" + seek + " " + buffer.size()); // TODO
127+ if (buffer.size() > seek) {
128+ int b = buffer.get(seek);
129+ if (b < 0) {
130+ b += 256;
131+ }
132+ seek++;
133+ //System.out.println("! " + b); // TODO
134+ return b;
135+ } else if (seek > 0) {
136+ buffer.clear();
137+ seek = 0;
138+ }
139+ return -1;
140+ }
141+
142+ public synchronized void println(String text)
143+ {
144+ text += lineSeparator;
145+ for (Byte b : text.getBytes(charset)) {
146+ buffer.add(b);
147+ }
148+ }
149+
150+ public InputStream getIn()
151+ {
152+ return in;
153+ }
154+
155+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/swing/components/ContainerSenderAndReceiver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/swing/components/ContainerSenderAndReceiver.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,56 @@
1+package mirrg.swing.components;
2+
3+import java.awt.Component;
4+import java.nio.charset.Charset;
5+
6+import javax.swing.BorderFactory;
7+import javax.swing.JComponent;
8+
9+import jp.hishidama.swing.layout.GroupLayoutUtil;
10+
11+public class ContainerSenderAndReceiver extends JComponent
12+{
13+
14+ private ContainerReceiver containerReceiver;
15+ private ContainerSender containerSender;
16+
17+ public ContainerSenderAndReceiver(Charset charset)
18+ {
19+
20+ containerReceiver = new ContainerReceiver(charset);
21+ containerReceiver.setBorder(BorderFactory.createTitledBorder("受信"));
22+
23+ containerSender = new ContainerSender(charset, false);
24+ containerSender.setBorder(BorderFactory.createTitledBorder("送信"));
25+
26+ {
27+ Component[][] compos = {
28+ {
29+ containerSender,
30+ },
31+ {
32+ containerReceiver,
33+ },
34+ };
35+
36+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
37+
38+ groupLayoutUtil.setComponents(compos);
39+ groupLayoutUtil.setGroupLayoutTo(this);
40+
41+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(false);
42+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
43+ }
44+ }
45+
46+ public ContainerReceiver getContainerReceiver()
47+ {
48+ return containerReceiver;
49+ }
50+
51+ public ContainerSender getContainerSender()
52+ {
53+ return containerSender;
54+ }
55+
56+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/swing/frames/FrameReceiver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/swing/frames/FrameReceiver.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,79 @@
1+package mirrg.swing.frames;
2+
3+import java.awt.Component;
4+import java.awt.Container;
5+import java.io.OutputStream;
6+import java.io.PrintStream;
7+import java.nio.charset.Charset;
8+
9+import javax.swing.JButton;
10+
11+import jp.hishidama.swing.layout.GroupLayoutUtil;
12+import mirrg.swing.components.ContainerReceiver;
13+import mirrg.util.FrameMirrg;
14+
15+public class FrameReceiver extends FrameMirrg
16+{
17+
18+ private ContainerReceiver containerReceiver;
19+
20+ public FrameReceiver()
21+ {
22+ this(Charset.forName("UTF-16"));
23+ }
24+
25+ public FrameReceiver(Charset charset)
26+ {
27+ this(charset, "受信フォーム");
28+ }
29+
30+ public FrameReceiver(Charset charset, String title)
31+ {
32+ super(title);
33+
34+ Container container = this.getContentPane();
35+ {
36+ containerReceiver = new ContainerReceiver(charset);
37+
38+ JButton button1 = new JButton("閉じる");
39+ button1.addActionListener(e -> {
40+ dispose();
41+ });
42+
43+ {
44+ Component[][] compos = {
45+ {
46+ containerReceiver,
47+ },
48+ {
49+ button1,
50+ },
51+ };
52+
53+ GroupLayoutUtil groupLayoutUtil = new GroupLayoutUtil();
54+
55+ groupLayoutUtil.setComponents(compos);
56+ groupLayoutUtil.setGroupLayoutTo(container);
57+
58+ groupLayoutUtil.getGroupLayout().setAutoCreateContainerGaps(false);
59+ groupLayoutUtil.getGroupLayout().setAutoCreateGaps(true);
60+ }
61+ }
62+
63+ prepareFrame();
64+ }
65+
66+ public OutputStream getOut()
67+ {
68+ return containerReceiver.out;
69+ }
70+
71+ public static FrameReceiver accept(Exception e)
72+ {
73+ FrameReceiver frameReceiver = new FrameReceiver();
74+ frameReceiver.setVisible(true);
75+ e.printStackTrace(new PrintStream(frameReceiver.getOut()));
76+ return frameReceiver;
77+ }
78+
79+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/swing/frames/FrameSender.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/swing/frames/FrameSender.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,41 @@
1+package mirrg.swing.frames;
2+
3+import java.awt.CardLayout;
4+import java.awt.Container;
5+import java.io.InputStream;
6+import java.nio.charset.Charset;
7+
8+import mirrg.swing.components.ContainerSender;
9+import mirrg.util.FrameMirrg;
10+
11+public class FrameSender extends FrameMirrg
12+{
13+
14+ public ContainerSender containerSender;
15+
16+ public FrameSender(Charset charset, boolean blocking)
17+ {
18+ this(charset, "送信フォーム", blocking);
19+ }
20+
21+ public FrameSender(Charset charset, String title, boolean blocking)
22+ {
23+ super(title);
24+
25+ Container container = this.getContentPane();
26+ {
27+ containerSender = new ContainerSender(charset, blocking);
28+ container.add(containerSender);
29+
30+ container.setLayout(new CardLayout());
31+ }
32+
33+ prepareFrame();
34+ }
35+
36+ public InputStream getIn()
37+ {
38+ return containerSender.in;
39+ }
40+
41+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/util/FrameMirrg.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/util/FrameMirrg.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,98 @@
1+package mirrg.util;
2+
3+import java.awt.GraphicsConfiguration;
4+import java.awt.HeadlessException;
5+import java.awt.event.WindowEvent;
6+import java.awt.event.WindowListener;
7+import java.util.function.Consumer;
8+
9+import javax.swing.JFrame;
10+import javax.swing.WindowConstants;
11+
12+public class FrameMirrg extends JFrame
13+{
14+
15+ public FrameMirrg() throws HeadlessException
16+ {
17+ super();
18+ }
19+
20+ public FrameMirrg(GraphicsConfiguration gc)
21+ {
22+ super(gc);
23+ }
24+
25+ public FrameMirrg(String title) throws HeadlessException
26+ {
27+ super(title);
28+ }
29+
30+ public FrameMirrg(String title, GraphicsConfiguration gc)
31+ {
32+ super(title, gc);
33+ }
34+
35+ public void onClosed(Consumer<WindowEvent> consumer)
36+ {
37+ addWindowListener(new WindowListener() {
38+
39+ @Override
40+ public void windowOpened(WindowEvent e)
41+ {
42+
43+ }
44+
45+ @Override
46+ public void windowIconified(WindowEvent e)
47+ {
48+
49+ }
50+
51+ @Override
52+ public void windowDeiconified(WindowEvent e)
53+ {
54+
55+ }
56+
57+ @Override
58+ public void windowDeactivated(WindowEvent e)
59+ {
60+
61+ }
62+
63+ @Override
64+ public void windowClosing(WindowEvent e)
65+ {
66+
67+ }
68+
69+ @Override
70+ public void windowClosed(WindowEvent e)
71+ {
72+ consumer.accept(e);
73+ }
74+
75+ @Override
76+ public void windowActivated(WindowEvent e)
77+ {
78+
79+ }
80+
81+ });
82+ }
83+
84+ protected void showAndDisposeOnClose()
85+ {
86+ prepareFrame();
87+ setVisible(true);
88+ }
89+
90+ protected void prepareFrame()
91+ {
92+ setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
93+
94+ pack();
95+ setLocationByPlatform(true);
96+ }
97+
98+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/util/HFrame.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/util/HFrame.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,17 @@
1+package mirrg.util;
2+
3+import java.awt.Font;
4+
5+public class HFrame
6+{
7+
8+ // TODO Win限日本限
9+ private static Font editableTextFont = new Font("MS Gothic", Font.PLAIN, 12);
10+
11+ public static Font getEditableMonospaceFont()
12+ {
13+ //return new TextField().getFont(); // Monospaceじゃない
14+ return editableTextFont;
15+ }
16+
17+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/util/HString.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/util/HString.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,106 @@
1+package mirrg.util;
2+
3+import static org.junit.Assert.*;
4+
5+import java.util.regex.Matcher;
6+import java.util.regex.Pattern;
7+
8+import org.junit.Test;
9+
10+public class HString
11+{
12+
13+ @Test
14+ public void test_getIndexedFilePath()
15+ {
16+ assertEquals("aaa.txt", getIndexedFilePath("aaa.txt", 0));
17+ assertEquals("b\\aaa.txt", getIndexedFilePath("b\\aaa.txt", 0));
18+ assertEquals("c:\\aaa.txt", getIndexedFilePath("c:\\aaa.txt", 0));
19+ assertEquals("c:\\b\\aaa.txt", getIndexedFilePath("c:\\b\\aaa.txt", 0));
20+ assertEquals("aaa_1.txt", getIndexedFilePath("aaa.txt", 1));
21+ assertEquals("b\\aaa_1.txt", getIndexedFilePath("b\\aaa.txt", 1));
22+ assertEquals("c:\\aaa_1.txt", getIndexedFilePath("c:\\aaa.txt", 1));
23+ assertEquals("c:\\b\\aaa_1.txt", getIndexedFilePath("c:\\b\\aaa.txt", 1));
24+ assertEquals("aaa_2.txt", getIndexedFilePath("aaa.txt", 2));
25+ assertEquals("b\\aaa_2.txt", getIndexedFilePath("b\\aaa.txt", 2));
26+ assertEquals("c:\\aaa_2.txt", getIndexedFilePath("c:\\aaa.txt", 2));
27+ assertEquals("c:\\b\\aaa_2.txt", getIndexedFilePath("c:\\b\\aaa.txt", 2));
28+ }
29+
30+ @Test
31+ public void test_toString()
32+ {
33+ assertEquals("0", HString.toString(0.0));
34+ assertEquals("190", HString.toString(190D));
35+ assertEquals("-56", HString.toString(-56));
36+ assertEquals("1000", HString.toString(10E2));
37+ assertEquals("1000.0001", HString.toString(10.000001E2));
38+ assertEquals("0.010000001", HString.toString(10.000001E-3));
39+ assertEquals("0.1234567", HString.toString(0.1234567));
40+ assertEquals("0.1234567891", HString.toString(0.1234567891));
41+ assertEquals("0.12345678912345678", HString.toString(0.12345678912345678912345));
42+ assertEquals("1000000000000000000", HString.toString(1000000000000000000D));
43+ assertEquals("-0", HString.toString(-0.0));
44+ }
45+
46+ private final static Pattern extension = Pattern.compile("\\.(?=[^\\.]*\\Z)");
47+
48+ public static String getIndexedFilePath(String filePath, int index)
49+ {
50+ if (index == 0) return filePath;
51+
52+ String prefix;
53+ String suffix;
54+ {
55+ Matcher m = extension.matcher(filePath);
56+ if (m.find()) {
57+ prefix = filePath.substring(0, m.start());
58+ suffix = m.group() + filePath.substring(m.end());
59+ } else {
60+ prefix = filePath;
61+ suffix = "";
62+ }
63+ }
64+
65+ return prefix + "_" + index + suffix;
66+ }
67+
68+ public static String toString(double value)
69+ {
70+ StringBuffer sb = new StringBuffer(String.format("%.18f", value));
71+
72+ while (sb.charAt(sb.length() - 1) == '0') {
73+ sb.setLength(sb.length() - 1);
74+ }
75+
76+ if (sb.charAt(sb.length() - 1) == '.') {
77+ sb.setLength(sb.length() - 1);
78+ }
79+
80+ return sb.toString();
81+ }
82+
83+ private static final Pattern patternFileNameExtension =
84+ Pattern.compile("\\.([^\\.\\\\]+)\\Z");
85+
86+ public static String deleteExtension(String filename)
87+ {
88+ Matcher matcher = patternFileNameExtension.matcher(filename);
89+ if (matcher.find()) {
90+ return filename.substring(0, matcher.start());
91+ } else {
92+ return filename;
93+ }
94+ }
95+
96+ @Test
97+ public void test()
98+ {
99+ assertEquals("C:\\a\\b", deleteExtension("C:\\a\\b.csv"));
100+ assertEquals("C:\\a\\b.", deleteExtension("C:\\a\\b."));
101+ assertEquals("C:\\a\\b", deleteExtension("C:\\a\\b"));
102+ assertEquals("C:\\a\\b.csv", deleteExtension("C:\\a\\b.csv.txt"));
103+ assertEquals("C:\\a.b\\c", deleteExtension("C:\\a.b\\c"));
104+ }
105+
106+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/util/Tuple.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/util/Tuple.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,25 @@
1+package mirrg.util;
2+
3+public class Tuple<X, Y>
4+{
5+
6+ private X x;
7+ private Y y;
8+
9+ public Tuple(X x, Y y)
10+ {
11+ this.x = x;
12+ this.y = y;
13+ }
14+
15+ public X getX()
16+ {
17+ return x;
18+ }
19+
20+ public Y getY()
21+ {
22+ return y;
23+ }
24+
25+}
diff -r 000000000000 -r 2cc40d8f37a4 src/mirrg/util/UTF8StreamReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mirrg/util/UTF8StreamReader.java Fri Jun 26 17:39:33 2015 +0900
@@ -0,0 +1,77 @@
1+package mirrg.util;
2+
3+import java.io.IOException;
4+import java.io.InputStream;
5+import java.io.UncheckedIOException;
6+import java.nio.charset.Charset;
7+import java.util.ArrayList;
8+import java.util.function.Consumer;
9+
10+public class UTF8StreamReader
11+{
12+
13+ private static final Charset charset = Charset.forName("UTF-8");
14+ private InputStream in;
15+ private boolean blocking;
16+
17+ public UTF8StreamReader(InputStream in, boolean blocking)
18+ {
19+ this.in = in;
20+ this.blocking = blocking;
21+ }
22+
23+ private ArrayList<Byte> buffer = new ArrayList<>();
24+
25+ public void stream(Consumer<String> consumer)
26+ {
27+ boolean r = false;
28+
29+ while (true) {
30+ int b;
31+ try {
32+ b = in.read();
33+ //System.out.println((char)b); // TODO
34+ } catch (IOException e) {
35+ throw new UncheckedIOException(e);
36+ }
37+ if (b < 0) {
38+ if (blocking) {
39+ flush(consumer);
40+ break;
41+ }
42+ } else if ((char) b == '\r') {
43+ r = true;
44+ flush(consumer);
45+ buffer.clear();
46+ continue;
47+ } else if ((char) b == '\n') {
48+ if (r) {
49+
50+ } else {
51+ flush(consumer);
52+ buffer.clear();
53+ }
54+ continue;
55+ } else {
56+ buffer.add((byte) b);
57+ continue;
58+ }
59+
60+ try {
61+ Thread.sleep(1);
62+ } catch (InterruptedException e) {
63+ break;
64+ }
65+ }
66+ }
67+
68+ private void flush(Consumer<String> consumer)
69+ {
70+ byte[] buffer2 = new byte[buffer.size()];
71+ for (int i = 0; i < buffer2.length; i++) {
72+ buffer2[i] = buffer.get(i);
73+ }
74+ consumer.accept(new String(buffer2, charset));
75+ }
76+
77+}