View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2024 Christian Kohlschütter
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.newsclub.net.unix.rmi;
19  
20  import java.io.FileDescriptor;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.ObjectInput;
24  
25  /**
26   * A specialized subclass of {@link RemoteFileDescriptorBase}, specifically for
27   * {@link FileOutputStream}s.
28   *
29   * @author Christian Kohlschütter
30   */
31  public final class RemoteFileOutput extends RemoteFileDescriptorBase<FileOutputStream> {
32    private static final long serialVersionUID = 1L;
33  
34    /**
35     * Creates an uninitialized instance; used for externalization.
36     *
37     * @see #readExternal(ObjectInput)
38     */
39    public RemoteFileOutput() {
40      super();
41    }
42  
43    /**
44     * Creates a new {@link RemoteFileOutput} instance, encapsulating a {@link FileOutputStream} so
45     * that it can be shared with other processes via RMI.
46     *
47     * @param socketFactory The socket factory.
48     * @param fout The {@link FileOutputStream}.
49     * @throws IOException if the operation fails.
50     */
51    public RemoteFileOutput(AFUNIXRMISocketFactory socketFactory, FileOutputStream fout)
52        throws IOException {
53      super(socketFactory, fout, fout.getFD(), RemoteFileDescriptorBase.MAGIC_VALUE_MASK
54          | RemoteFileDescriptorBase.BIT_WRITABLE);
55    }
56  
57    /**
58     * Returns a FileOutputStream for the given instance. This either is the actual instance provided
59     * by the constructor or a new instance created from the file descriptor.
60     *
61     * @return The FileOutputStream.
62     * @throws IOException if the operation fails.
63     */
64    public FileOutputStream asFileOutputStream() throws IOException {
65      if ((getMagicValue() & RemoteFileDescriptorBase.BIT_WRITABLE) == 0) {
66        throw new IOException("FileDescriptor is not writable");
67      }
68  
69      return resource.accumulateAndGet(null, (prev, x) -> {
70        if (prev != null) {
71          return prev;
72        }
73        FileDescriptor fd = getFileDescriptor();
74        if (!fd.valid()) {
75          throw new IllegalStateException("Invalid file descriptor");
76        }
77        return new FileOutputStream(fd) {
78          @Override
79          public synchronized void close() throws IOException {
80            RemoteFileOutput.this.close();
81            super.close();
82          }
83        };
84      });
85    }
86  }