All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mchange.sc.v1.util.ClosableUtils.scala Maven / Gradle / Ivy

The newest version!
/*
 * Distributed as part of mchange-commons-scala v0.4.0
 *
 * Copyright (C) 2015 Machinery For Change, Inc.
 *
 * Author: Steve Waldman 
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of EITHER:
 *
 *     1) The GNU Lesser General Public License (LGPL), version 2.1, as 
 *        published by the Free Software Foundation
 *
 * OR
 *
 *     2) The Eclipse Public License (EPL), version 1.0
 *
 * You may choose which license to accept if you wish to redistribute
 * or modify this work. You may offer derivatives of this work
 * under the license you have chosen, or you may provide the same
 * choice of license which you have been offered here.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received copies of both LGPL v2.1 and EPL v1.0
 * along with this software; see the files LICENSE-EPL and LICENSE-LGPL.
 * If not, the text of these licenses are currently available at
 *
 * LGPL v2.1: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *  EPL v1.0: http://www.eclipse.org/org/documents/epl-v10.php 
 * 
 */

package com.mchange.sc.v1.util;

import com.mchange.v2.reflect.ReflectUtils;
import java.lang.reflect.Method;

/**
 *  A bug with Scala's duck typing implementation
 *  allows methods of non-public classes that implement
 *  public interfaces (or override public base class methods)
 *  to get invoked directly on the non-public class' member
 *  (which is illegal and provokes an IllegalAccessException)
 *  rather than indirectly via the public parent class or
 *  interface method. The safeClose / ReflectUtils stuff
 *  is to work around that. When Scala's duck type bugs are
 *  fixed, this should be removed.
 */ 

object ClosableUtils
{
  private val emptyClassArray = new Array[Class[Any]](0);
  private val emptyObjArray   = new Array[Object](0);
  
  type Closable = { def close() : Unit };
  type Destroyable = { def destroy() : Unit };

  private def safeClose( closable : Closable ) : Unit = {
      val m = closable.getClass().getMethod("close", emptyClassArray : _* );
      val accessibleM = ReflectUtils.findInPublicScope( m );
      accessibleM.invoke( closable, emptyObjArray : _* );
  }


  def attemptClose( closable : Closable ) : Unit = 
    {
      try { if (closable != null) /* closable.close(); */ safeClose( closable ); }
      catch { case ex : Exception => ex.printStackTrace(); }
      //println("closed " + closable); new Exception("DEBUG").printStackTrace();
    }

  def attemptClose( c1 : Closable, c2 : Closable, closables : Closable* ) : Unit = 
    { attemptClose(c1); attemptClose(c2); closables.foreach( attemptClose _ ); }

  def attemptCloseAll( closables : Closable* ) : Unit = 
    { closables.foreach( attemptClose _ ); }

  def withClosable[T <: Closable, A]( factoryMethod : () => T )( op : (T) => A ) : A = {
    val rsrc : T = factoryMethod();

    try
    { op(rsrc); }
    finally
    { attemptClose( rsrc ) ; }
  }

  private class Destroyable2Closable[T <: Destroyable]( val rsrc : T )
  {
    // def close() : Unit = rsrc.destroy();
    //
    // have to work around Scala bug (Trac Ticket #2318)

    def close() : Unit = {
      val m = rsrc.getClass().getMethod("destroy", emptyClassArray : _*);
      val accessibleM = ReflectUtils.findInPublicScope( m );
      accessibleM.invoke( rsrc, emptyObjArray : _*);
    }
  }

  def withDestroyable[T <: Destroyable]( factoryMethod : () => T )( op : (T) => Unit ) : Unit =
    withClosable( () => new Destroyable2Closable[T]( factoryMethod() ) ){ d2c => op( d2c.rsrc ) };

/* TOO CUMBERSOME

  def withFourClosables[A <: Closable, B <: Closable, C <: Closable, D <: Closable](factoryA : () => A , 
										    factoryB : (A) => B,
										    factoryC : (A,B) => C,
										    factoryD : (A,B,C) => D) ( op : (Tuple4[A,B,C,D]) => Unit ) {
    withClosable( factoryA ) {
      a =>
	withClosable( () => factoryB(a) ) {
	  b =>
	    withClosable( () => factoryC(a,b) ) {
	      c => 
		withClosable( () => factoryD(a,b,c) ) {
		  d =>
		    op( Tuple4(a, b, c, d ) ); 
		}
	    }
	}
    }
  }
*/
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy