1
1
/*
2
- * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
3
3
*
4
4
* This program and the accompanying materials are made available under the
5
5
* terms of the Eclipse Public License v. 2.0, which is available at
16
16
17
17
package jakarta .mail .util ;
18
18
19
- import org .junit .Test ;
19
+ import static org .junit .Assert .assertEquals ;
20
+ import static org .junit .Assert .fail ;
21
+
22
+ import jakarta .mail .util .SharedFileInputStream .SharedFile ;
20
23
21
24
import java .io .File ;
22
25
import java .io .IOException ;
23
26
import java .io .InputStream ;
27
+ import java .io .RandomAccessFile ;
28
+ import java .lang .ref .PhantomReference ;
29
+ import java .lang .ref .Reference ;
30
+ import java .lang .ref .ReferenceQueue ;
31
+ import java .lang .reflect .Field ;
32
+ import java .util .concurrent .TimeoutException ;
24
33
25
- import static org .junit .Assert . fail ;
34
+ import org .junit .Test ;
26
35
27
36
/**
28
37
* Please note:
@@ -62,4 +71,93 @@ public void testGrandChild() throws Exception {
62
71
file .delete ();
63
72
}
64
73
}
74
+
75
+ @ Test
76
+ public void testCloseMultipleTimes () throws Exception {
77
+ File file = new File (SharedFileInputStreamTest .class .getResource ("/jakarta/mail/util/sharedinputstream.txt" ).toURI ());
78
+ SharedFileInputStream in = new SharedFileInputStream (file );
79
+ in .close ();
80
+ in .close ();
81
+ }
82
+
83
+ @ Test
84
+ public void testOpenIfOneOpened () throws Exception {
85
+ File file = new File (SharedFileInputStreamTest .class .getResource ("/jakarta/mail/util/sharedinputstream.txt" ).toURI ());
86
+ SharedFileInputStream in0 = null ;
87
+ SharedFileInputStream in1 = null ;
88
+ try (SharedFileInputStream in = new SharedFileInputStream (file )) {
89
+ in0 = (SharedFileInputStream ) in .newStream (0 , 6 );
90
+ in1 = (SharedFileInputStream ) in .newStream (6 , 12 );
91
+ }
92
+ RandomAccessFile ra0 = getRandomAccessFile (in0 );
93
+ RandomAccessFile ra1 = getRandomAccessFile (in1 );
94
+ // It is the same instance
95
+ assertEquals (ra0 , ra1 );
96
+ // RandomAccessFile still be open
97
+ in1 .close ();
98
+ assertEquals (false , isClosed (ra1 ));
99
+ in0 .close ();
100
+ // All SharedFileInputStream are closed, so RandomAccessFile gets closed too
101
+ assertEquals (true , isClosed (ra1 ));
102
+ }
103
+
104
+ @ Test
105
+ public void testGC () throws Exception {
106
+ File file = new File (SharedFileInputStreamTest .class .getResource ("/jakarta/mail/util/sharedinputstream.txt" ).toURI ());
107
+ SharedFileInputStream in = new SharedFileInputStream (file );
108
+ GCUtil gcUtil = new GCUtil (in );
109
+ SharedFileInputStream in0 = (SharedFileInputStream ) in .newStream (0 , 6 );
110
+ in .close ();
111
+ in = null ;
112
+ gcUtil .waitTillGCed (1000 );
113
+ gcUtil = new GCUtil (in0 );
114
+ SharedFileInputStream in1 = (SharedFileInputStream ) in0 .newStream (6 , 12 );
115
+ assertEquals ("test0\n " , new String (in0 .readAllBytes ()));
116
+ in0 .close ();
117
+ in0 = null ;
118
+ gcUtil .waitTillGCed (1000 );
119
+ assertEquals ("test1\n " , new String (in1 .readAllBytes ()));
120
+ in1 .close ();
121
+ }
122
+
123
+ private RandomAccessFile getRandomAccessFile (SharedFileInputStream in ) throws Exception {
124
+ Field f1 = SharedFileInputStream .class .getDeclaredField ("sf" );
125
+ f1 .setAccessible (true );
126
+ SharedFile rin = (SharedFile ) f1 .get (in );
127
+ RandomAccessFile rf = rin .in ;
128
+ return rf ;
129
+ }
130
+
131
+ private boolean isClosed (RandomAccessFile rf ) throws Exception {
132
+ try {
133
+ rf .readByte ();
134
+ return false ;
135
+ } catch (IOException e ) {
136
+ return true ;
137
+ }
138
+ }
139
+
140
+ private static class GCUtil {
141
+
142
+ private final ReferenceQueue <Object > rq = new ReferenceQueue <>();
143
+ private final PhantomReference <Object > phantomRef ;
144
+
145
+ private GCUtil (Object ref ) {
146
+ phantomRef = new PhantomReference <>(ref , rq );
147
+ }
148
+
149
+ private void waitTillGCed (long timeout ) throws Exception {
150
+ Reference <? extends Object > gced ;
151
+ long time = 0 ;
152
+ long sleep = 100 ;
153
+ while ((gced = rq .poll ()) != phantomRef ) {
154
+ Thread .sleep (sleep );
155
+ time = time + sleep ;
156
+ if (time >= timeout ) {
157
+ throw new TimeoutException ("Instance not GCed after " + timeout + " millis" );
158
+ }
159
+ System .gc ();
160
+ }
161
+ }
162
+ }
65
163
}
0 commit comments