FileDescriptorIO.java

  1. /***** BEGIN LICENSE BLOCK *****
  2.  * Version: EPL 1.0/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Eclipse Public
  5.  * License Version 1.0 (the "License"); you may not use this file
  6.  * except in compliance with the License. You may obtain a copy of
  7.  * the License at http://www.eclipse.org/legal/epl-v10.html
  8.  *
  9.  * Software distributed under the License is distributed on an "AS
  10.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.  * implied. See the License for the specific language governing
  12.  * rights and limitations under the License.
  13.  *
  14.  * Copyright (C) 2008 JRuby project
  15.  *
  16.  * Alternatively, the contents of this file may be used under the terms of
  17.  * either of the GNU General Public License Version 2 or later (the "GPL"),
  18.  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  19.  * in which case the provisions of the GPL or the LGPL are applicable instead
  20.  * of those above. If you wish to allow use of your version of this file only
  21.  * under the terms of either the GPL or the LGPL, and not to allow others to
  22.  * use your version of this file under the terms of the EPL, indicate your
  23.  * decision by deleting the provisions above and replace them with the notice
  24.  * and other provisions required by the GPL or the LGPL. If you do not delete
  25.  * the provisions above, a recipient may use your version of this file under
  26.  * the terms of any one of the EPL, the GPL or the LGPL.
  27.  ***** END LICENSE BLOCK *****/

  28. package org.jruby.ext.ffi.io;

  29. import jnr.posix.FileStat;
  30. import org.jruby.Ruby;
  31. import org.jruby.RubyClass;
  32. import org.jruby.RubyIO;
  33. import org.jruby.RubyModule;
  34. import org.jruby.RubyNumeric;
  35. import org.jruby.anno.JRubyClass;
  36. import org.jruby.anno.JRubyMethod;
  37. import org.jruby.runtime.ObjectAllocator;
  38. import org.jruby.runtime.ThreadContext;
  39. import org.jruby.runtime.builtin.IRubyObject;
  40. import org.jruby.util.io.ModeFlags;

  41. import java.nio.channels.ByteChannel;

  42. /**
  43.  * An IO implementation that reads/writes to a native file descriptor.
  44.  */
  45. @JRubyClass(name="FFI::" + FileDescriptorIO.CLASS_NAME, parent="IO")
  46. public class FileDescriptorIO extends RubyIO {
  47.     public static final String CLASS_NAME = "FileDescriptorIO";
  48.     private static final class Allocator implements ObjectAllocator {
  49.         public final IRubyObject allocate(Ruby runtime, RubyClass klass) {
  50.             return new FileDescriptorIO(runtime, klass);
  51.         }
  52.         private static final ObjectAllocator INSTANCE = new Allocator();
  53.     }

  54.     public FileDescriptorIO(Ruby runtime, RubyClass klass) {
  55.         super(runtime, klass);
  56.         MakeOpenFile();
  57.     }

  58.     public FileDescriptorIO(Ruby runtime, IRubyObject fd) {
  59.         super(runtime, runtime.getModule("FFI").getClass(CLASS_NAME));
  60.         MakeOpenFile();
  61.         ModeFlags modes = newModeFlags(runtime, ModeFlags.RDWR);
  62.         int fileno = RubyNumeric.fix2int(fd);
  63.         FileStat stat = runtime.getPosix().fstat(fileno);
  64.         ByteChannel channel;

  65.         if (stat.isSocket()) {
  66.             channel = new jnr.enxio.channels.NativeSocketChannel(fileno);
  67.         } else if (stat.isBlockDev() || stat.isCharDev()) {
  68.             channel = new jnr.enxio.channels.NativeDeviceChannel(fileno);
  69.         } else {
  70.             channel = new FileDescriptorByteChannel(runtime, fileno);
  71.         }

  72. //        openFile.setMainStream(ChannelStream.open(getRuntime(), new ChannelDescriptor(channel, modes, FileDescriptorHelper.wrap(fileno))));
  73.         openFile.setChannel(channel);
  74.         openFile.setMode(modes.getOpenFileFlags());
  75.         openFile.setMode(modes.getOpenFileFlags());
  76.         openFile.setSync(true);
  77.     }

  78.     public static RubyClass createFileDescriptorIOClass(Ruby runtime, RubyModule module) {
  79.         RubyClass result = runtime.defineClassUnder(CLASS_NAME, runtime.getClass("IO"),
  80.                 Allocator.INSTANCE, module);
  81.         result.defineAnnotatedMethods(FileDescriptorIO.class);
  82.         result.defineAnnotatedConstants(FileDescriptorIO.class);

  83.         return result;
  84.     }

  85.     @JRubyMethod(name = "new", meta = true)
  86.     public static FileDescriptorIO newInstance(ThreadContext context, IRubyObject recv, IRubyObject fd) {
  87.         return new FileDescriptorIO(context.runtime, fd);
  88.     }

  89.     @JRubyMethod(name = "wrap", required = 1, meta = true)
  90.     public static RubyIO wrap(ThreadContext context, IRubyObject recv, IRubyObject fd) {
  91.         return new FileDescriptorIO(context.runtime, fd);
  92.     }

  93.     static class FileDescriptorHelper {
  94.         static java.lang.reflect.Constructor<java.io.FileDescriptor> CONSTRUCTOR;
  95.         static {
  96.             java.lang.reflect.Constructor<java.io.FileDescriptor> constructor;
  97.             try {
  98.                 constructor = java.io.FileDescriptor.class.getDeclaredConstructor(int.class);
  99.                 constructor.setAccessible(true);
  100.             } catch (Throwable t) {
  101.                 constructor = null;
  102.             }
  103.             CONSTRUCTOR = constructor;
  104.         }

  105.         public static java.io.FileDescriptor wrap(int fileno) {
  106.             try {
  107.                 return CONSTRUCTOR != null ? CONSTRUCTOR.newInstance(fileno) : new java.io.FileDescriptor();
  108.             } catch (IllegalAccessException iae) {
  109.                 return new java.io.FileDescriptor();
  110.             } catch (InstantiationException ie) {
  111.                 return new java.io.FileDescriptor();
  112.             } catch (java.lang.reflect.InvocationTargetException ite) {
  113.                 return new java.io.FileDescriptor();
  114.             }
  115.         }
  116.     }
  117. }