アルファ版。新版→https://osdn.jp/users/tacticsrealize/pf/ChlorophyllUploader/wiki/FrontPage
修訂 | 2cc40d8f37a47e4a1c86ef6d62685f2a726efab0 (tree) |
---|---|
時間 | 2015-06-26 17:39:33 |
作者 | <15b05@15b0...> |
add project
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |