001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.util;
021    
022    import java.lang.reflect.Constructor;
023    import java.lang.reflect.InvocationHandler;
024    import java.lang.reflect.Method;
025    import java.lang.reflect.Proxy;
026    import java.util.logging.Level;
027    import java.util.logging.Logger;
028    
029    public class InterruptHandler {
030    
031      /** . */
032      private final Runnable runnable;
033    
034      /** . */
035      private final Logger log = Logger.getLogger(InterruptHandler.class.getName());
036    
037      private final InvocationHandler handler = new InvocationHandler() {
038        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
039          Class<?>[] parameterTypes = method.getParameterTypes();
040          if (method.getName().equals("hashCode") && parameterTypes.length == 0) {
041            return System.identityHashCode(runnable);
042          } else if (method.getName().equals("equals") && parameterTypes.length == 1 && parameterTypes[0] == Object.class) {
043            return runnable.equals(args[0]);
044          } else if (method.getName().equals("toString") && parameterTypes.length == 0) {
045            return runnable.toString();
046          } else if (method.getName().equals("handle")) {
047            runnable.run();
048            return null;
049          } else {
050            throw new UnsupportedOperationException("Method " + method + " not implemented");
051          }
052        }
053      };
054    
055      public InterruptHandler(Runnable runnable) {
056        this.runnable = runnable;
057      }
058    
059      public void install() {
060        ClassLoader cl = Thread.currentThread().getContextClassLoader();
061        Class<?> signalHandlerClass;
062        Class<?> signalClass;
063        Method handle;
064        Object INT;
065        try {
066          signalHandlerClass = cl.loadClass("sun.misc.SignalHandler");
067          signalClass = cl.loadClass("sun.misc.Signal");
068          handle = signalClass.getDeclaredMethod("handle", signalClass, signalHandlerClass);
069          Constructor ctor = signalClass.getConstructor(String.class);
070          INT = ctor.newInstance("INT");
071        }
072        catch (Exception e) {
073          return;
074        }
075    
076        //
077        Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{signalHandlerClass}, handler);
078    
079        //
080        try {
081          handle.invoke(null, INT, proxy);
082        }
083        catch (Exception e) {
084          log.log(Level.SEVERE, "Could not install signal handler", e);
085        }
086      }
087    }