blob: 99c5d3c48ec3203e685fcd3586bc36b7e0fff32a [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.checkstyle;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import java.io.IOException;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static java.nio.file.StandardOpenOption.*;
/**
* Main program for executing scenario test warden.
*/
public final class Main {
private static long POLLING_INTERVAL = 1000; //ms
// Public construction forbidden
private Main(String[] args) {
}
/**
* Main entry point for the cell warden.
*
* @param args command-line arguments
*/
public static void main(String[] args)
throws CheckstyleException, IOException {
startServer(args);
}
// Monitors another PID and exit when that process exits
private static void watchProcess(String pid) {
if (pid == null || pid.equals("0")) {
return;
}
Timer timer = new Timer(true); // start as a daemon, so we don't hang shutdown
timer.scheduleAtFixedRate(new TimerTask() {
private String cmd = "kill -s 0 " + pid;
@Override
public void run() {
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
if (p.exitValue() != 0) {
System.err.println("shutting down...");
System.exit(0);
}
} catch (IOException | InterruptedException e) {
//no-op
e.printStackTrace();
}
}
}, POLLING_INTERVAL, POLLING_INTERVAL);
}
// Initiates a server.
private static void startServer(String[] args) throws IOException, CheckstyleException {
String portLock = args[0];
String buckPid = args[1];
String checkstyleFile = args[2];
String suppressionsFile = args[3];
// Use a file lock to ensure only one copy of the daemon runs
Path portLockPath = Paths.get(portLock);
FileChannel channel = FileChannel.open(portLockPath, WRITE, CREATE);
FileLock lock = channel.tryLock();
if (lock == null) {
System.out.println("Server is already running");
System.exit(1);
} //else, hold the lock until the JVM exits
// Start the server and bind it to a random port
ServerSocket server = new ServerSocket(0);
// Monitor the parent buck process
watchProcess(buckPid);
// Set up hook to clean up after ourselves
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
if (channel != null) {
channel.truncate(0);
channel.close();
}
System.err.println("tear down...");
Files.delete(portLockPath);
} catch (IOException e) {
//no-op: shutting down
e.printStackTrace();
}
}));
// Write the bound port to the port file
int port = server.getLocalPort();
channel.truncate(0);
channel.write(ByteBuffer.wrap(Integer.toString(port).getBytes()));
// Instantiate a Checkstyle runner and executor; serve until exit...
CheckstyleRunner runner = new CheckstyleRunner(checkstyleFile, suppressionsFile);
ExecutorService executor = Executors.newCachedThreadPool();
while (true) {
try {
executor.submit(runner.checkClass(server.accept()));
} catch (Exception e) {
e.printStackTrace();
//no-op
}
}
}
}