1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.tools.sjavac.comp;
  26 
  27 import java.io.File;
  28 import java.net.URI;
  29 import java.util.List;
  30 import java.util.Objects;
  31 import java.util.Set;
  32 import java.util.concurrent.Callable;
  33 import java.util.concurrent.ExecutorService;
  34 import java.util.concurrent.Executors;
  35 import java.util.concurrent.ThreadFactory;
  36 import java.util.concurrent.TimeUnit;
  37 import java.util.concurrent.atomic.AtomicInteger;
  38 
  39 import com.sun.tools.sjavac.Log;
  40 import com.sun.tools.sjavac.server.CompilationResult;
  41 import com.sun.tools.sjavac.server.Sjavac;
  42 import com.sun.tools.sjavac.server.SysInfo;
  43 
  44 /**
  45  * An sjavac implementation that limits the number of concurrent calls by
  46  * wrapping invocations in Callables and delegating them to a FixedThreadPool.
  47  *
  48  *  <p><b>This is NOT part of any supported API.
  49  *  If you write code that depends on this, you do so at your own risk.
  50  *  This code and its internal interfaces are subject to change or
  51  *  deletion without notice.</b>
  52  */
  53 public class PooledSjavac implements Sjavac {
  54 
  55     final Sjavac delegate;
  56     final ExecutorService pool;
  57 
  58     public PooledSjavac(Sjavac delegate, int poolsize) {
  59         Objects.requireNonNull(delegate);
  60         this.delegate = delegate;
  61         pool = Executors.newFixedThreadPool(poolsize, new ThreadFactory() {
  62             AtomicInteger count = new AtomicInteger();
  63             @Override
  64             public Thread newThread(Runnable runnable) {
  65                 String cls = PooledSjavac.class.getSimpleName();
  66                 int num = count.incrementAndGet();
  67                 Thread t = new Thread(runnable, cls + "-" + num);
  68                 t.setDaemon(true);
  69                 return t;
  70             }
  71         });
  72     }
  73 
  74     @Override
  75     public SysInfo getSysInfo() {
  76         try {
  77             return pool.submit(new Callable<SysInfo>() {
  78                 @Override
  79                 public SysInfo call() throws Exception {
  80                     return delegate.getSysInfo();
  81                 }
  82             }).get();
  83         } catch (Exception e) {
  84             e.printStackTrace();
  85             throw new RuntimeException("Error during getSysInfo", e);
  86         }
  87     }
  88 
  89     @Override
  90     public CompilationResult compile(final String protocolId,
  91                                      final String invocationId,
  92                                      final String[] args,
  93                                      final List<File> explicitSources,
  94                                      final Set<URI> sourcesToCompile,
  95                                      final Set<URI> visibleSources) {
  96         try {
  97             return pool.submit(new Callable<CompilationResult>() {
  98                 @Override
  99                 public CompilationResult call() throws Exception {
 100                     return delegate.compile(protocolId,
 101                                             invocationId,
 102                                             args,
 103                                             explicitSources,
 104                                             sourcesToCompile,
 105                                             visibleSources);
 106                 }
 107             }).get();
 108         } catch (Exception e) {
 109             e.printStackTrace();
 110             throw new RuntimeException("Error during compile", e);
 111         }
 112     }
 113 
 114     @Override
 115     public void shutdown() {
 116         pool.shutdown(); // Disable new tasks from being submitted
 117         try {
 118             // Wait a while for existing tasks to terminate
 119             if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
 120                 pool.shutdownNow(); // Cancel currently executing tasks
 121                 // Wait a while for tasks to respond to being cancelled
 122                 if (!pool.awaitTermination(60, TimeUnit.SECONDS))
 123                     Log.error("ThreadPool did not terminate");
 124             }
 125             // Grace period for thread termination
 126             Thread.sleep(1000);
 127         } catch (InterruptedException ie) {
 128           // (Re-)Cancel if current thread also interrupted
 129           pool.shutdownNow();
 130           // Preserve interrupt status
 131           Thread.currentThread().interrupt();
 132         }
 133 
 134         delegate.shutdown();
 135     }
 136 
 137     @Override
 138     public String serverSettings() {
 139         return delegate.serverSettings();
 140     }
 141 }