Repository: flex-utilities Updated Branches: refs/heads/develop 495edeb1f -> e83f27a0a
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/5077c457/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/reporter/swf/SWFLineReporter.java ---------------------------------------------------------------------- diff --git a/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/reporter/swf/SWFLineReporter.java b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/reporter/swf/SWFLineReporter.java new file mode 100755 index 0000000..500917e --- /dev/null +++ b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/reporter/swf/SWFLineReporter.java @@ -0,0 +1,143 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.flex.tools.codecoverage.reporter.swf; + +import java.io.BufferedInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.util.Collection; + +import org.apache.commons.io.IOUtils; +import org.apache.flex.abc.ABCParser; +import org.apache.flex.compiler.clients.problems.CompilerProblemCategorizer; +import org.apache.flex.compiler.clients.problems.ProblemFormatter; +import org.apache.flex.compiler.clients.problems.ProblemPrinter; +import org.apache.flex.compiler.clients.problems.ProblemQuery; +import org.apache.flex.compiler.clients.problems.WorkspaceProblemFormatter; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.swf.TagType; +import org.apache.flex.swf.io.SWFReader; +import org.apache.flex.swf.tags.DoABCTag; +import org.apache.flex.swf.tags.ITag; +import org.apache.flex.tools.codecoverage.reporter.CoverageData; + +import com.google.common.collect.ImmutableList; + +/** + * Read in a SWF file and report the debugs line with the methods names. + * + * The data is returned in a Map where the key is the "path;package;file" string. + * The value is another Map where the key is the line number of the line. The + * value is a LineInfo object. + */ +public class SWFLineReporter +{ + + private final String path; + + /** + * Constructor. + * + * @param path The path of the SWF to read. + */ + public SWFLineReporter(final String path) + { + this.path = path; + } + + /** + * Read the debug lines from the SWF and populate the coverage data. + * + * @param coverageData The coverage data to add the debug lines to. + * @throws IOException + */ + public void readLines(final CoverageData coverageData) + throws IOException + { + final SWFReader swfReader = new SWFReader(false); + final URL url = new URL(path); + + try + { + swfReader.readFrom( + new BufferedInputStream(url.openStream()), + path); + + ProblemQuery problemQuery = new ProblemQuery(); + problemQuery.addAll(swfReader.getProblems()); + if (!problemQuery.hasErrors()) + { + final ImmutableList<ITag> tags = ImmutableList.copyOf(swfReader.iterator()); + for (ITag tag : tags) + { + // visit the DoABC tag + if (tag.getTagType() == TagType.DoABC) + { + processDoABC((DoABCTag)tag, coverageData); + } + } + } + + printProblems(swfReader.getProblems()); + } + catch (FileNotFoundException e) + { + System.err.println("Error: Unable read debug lines from " + e.getLocalizedMessage()); + throw e; + } + finally + { + IOUtils.closeQuietly(swfReader); + } + } + + /** + * Parse a DoABC record and add the debug lines to the coverage data. + * + * @param tag The ABC tag. + * @param coverageData The coverage data to populate. + */ + private void processDoABC(final DoABCTag tag, final CoverageData coverageData) + { + // create a visitor to record source line numbers. + final ABCParser parser = new ABCParser(tag.getABCData()); + final DebugLineVisitor debugLineVisitor = new DebugLineVisitor(coverageData); + parser.parseABC(debugLineVisitor); + } + + /** + * Print out problems to standard output. + * + * @param problems + */ + private void printProblems(final Collection<ICompilerProblem> problems) + { + final CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer(); + final ProblemFormatter formatter = new WorkspaceProblemFormatter(new Workspace(), + categorizer); + final ProblemPrinter printer = new ProblemPrinter(formatter, System.err); + + printer.printProblems(problems); + } + + +} http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/5077c457/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/CodeCoverageServer.java ---------------------------------------------------------------------- diff --git a/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/CodeCoverageServer.java b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/CodeCoverageServer.java new file mode 100755 index 0000000..73b4b06 --- /dev/null +++ b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/CodeCoverageServer.java @@ -0,0 +1,552 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.flex.tools.codecoverage.server; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.net.ConnectException; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +/** + * Main class of the Code Coverage Server. + * + * This class serves the command port. + * Creates threads to serve the data port and the policy file port. + * + */ +public class CodeCoverageServer +{ + private static enum ExitCode + { + SUCCESS(0), + HELP(1), + INVALID_OPTIONS(2), + ERRORS(3); + + private final int exitCode; + + private ExitCode(int exitCode) + { + this.exitCode = exitCode; + } + + public int getExitCode() + { + return exitCode; + } + } + + /** + * Commands + */ + public static final String START_COMMAND = "start"; + public static final String STOP_COMMAND = "stop"; + public static final String STATUS_COMMAND = "status"; + public static final String ALIVE_COMMAND = "alive"; + + /** + * Responses + */ + public static final String SUCCESS_RESPONSE = "0"; + public static final String ERROR_RESPONSE = "-1"; + + /** + * Default configuration values + */ + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_DATA_PORT = 9097; + private static final int DEFAULT_COMMAND_PORT = 9098; + private static final int DEFAULT_POLICY_FILE_PORT = 9843; + private static final String DEFAULT_PRELOAD_SWF = "CodeCoveragePreloadSWF.swf"; + + /** + * config.properties keys + */ + private static final String MM_CFG_PATH = "mmCfgPath"; + private static final String PRELOAD_SWF_KEY = "preloadSWF"; + private static final String DATA_DIRECTORY_KEY = "dataDirectory"; + private static final String HOST_KEY = "host"; + private static final String DATA_PORT_KEY = "dataPort"; + private static final String COMMAND_PORT_KEY = "commandPort"; + private static final String POLICY_FILE_PORT_KEY = "policyFilePort"; + + private static final boolean ADD_PRELOADSWF_KEY = true; + private static final boolean REMOVE_PRELOADSWF_KEY = false; + + private static final String CCSERVER_VERSION = "0.9"; + + private static boolean start; + private static boolean stop; + + /** + * @param args + */ + public static void main(String[] args) + { + CodeCoverageServer server = new CodeCoverageServer(); + final int exitCode = server.mainNoExit(args); + System.exit(exitCode); + } + + /** + * Entry point for the server instance. + * + * @param args Command line args + * @return One of EXIT_CODE enum. + */ + private int mainNoExit(String[] args) + { + System.out.println("Apache Flex Code Coverage Server"); + System.out.println("Version " + CCSERVER_VERSION); + System.out.println(""); + + if (args.length == 0 || + args.length == 1 && "-help".equals(args[0])) + { + System.out.println("Usage: ccserver [start | stop]"); + return ExitCode.HELP.getExitCode(); + } + + try + { + if (!initializeProperties()) + return ExitCode.INVALID_OPTIONS.getExitCode(); + + processArgs(args); + if (start) + start(); + else if (stop) + stop(); + } + catch (IOException e) + { + e.printStackTrace(); + return ExitCode.ERRORS.getExitCode(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + return ExitCode.ERRORS.getExitCode(); + } + + return ExitCode.SUCCESS.getExitCode(); + } + + private Properties config = new Properties(); + private boolean listening = true; + private String host; + private int dataPort; + private int commandPort; + private int policyFilePort; + private String preloadSWFPath; + + /** + * Constructor. + */ + public CodeCoverageServer() + { + } + + private void processArgs(final String[] args) + { + for (final String arg : args) + { + switch (arg) + { + case START_COMMAND: + { + start = true; + break; + } + case STOP_COMMAND: + { + stop = true; + break; + } + default: + { + System.err.println("unexpected argument " + arg); + } + } + } + } + + /** + * Starts the server. + * + * @throws IOException + * @throws InterruptedException + */ + public void start() throws IOException, InterruptedException + { + if (isAlive()) + { + System.out.println("Apache Flex Code Coverage Server is already running"); + return; + } + + final String dataProperty = config.getProperty(DATA_DIRECTORY_KEY, + System.getProperty("user.home")); + final File dataDirectory = new File(dataProperty, "ccdata"); + + if (!dataDirectory.exists()) + { + // mkdir() is creating the directory but returning false, so + // re-test with exists() + if (!dataDirectory.mkdir() && !dataDirectory.exists()) + { + System.err.println("Error: Data directory does not exist and unable to create it: " + dataDirectory.getAbsolutePath()); + return; + } + } + + // modify mm.cfg file + updateMMCFG(ADD_PRELOADSWF_KEY); + + // create thread to listen for connections on the data port + final DataSocketAccepter dataSocketAccepter = + new DataSocketAccepter(host, dataPort, dataDirectory); + final Thread dataThread = new Thread(dataSocketAccepter); + dataThread.start(); + + // create thread to listen the policy file port and server up the socket policy file. + final PolicyFileServer policyFileServer = new PolicyFileServer(host, + dataPort, policyFilePort); + final Thread policyFileServerThread = new Thread(policyFileServer); + policyFileServerThread.start(); + + System.out.println("listening on port " + dataPort); + + // read commands on command socket + final ServerSocket commandSocket = new ServerSocket(commandPort); + + try + { + while (listening) + { + try (Socket socket = commandSocket.accept(); + InputStreamReader reader = new InputStreamReader(socket.getInputStream()); + OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream())) + { + // wait for request + char[] cbuf = new char[256]; + int charsRead = reader.read(cbuf); + if (charsRead > 0) + { + processCommand(reader, writer, String.valueOf(cbuf).trim()); + } + } + } + } + finally + { + commandSocket.close(); + policyFileServer.close(); + policyFileServerThread.join(); + dataSocketAccepter.close(); + dataThread.join(); + updateMMCFG(REMOVE_PRELOADSWF_KEY); + } + + System.out.println("stopping Apache Flex Code Coverage Server"); + } + + /** + * Process a server command. + * + * @param reader The socket reader. + * @param writer The socket writer. + * @param command The command to process. + * @throws IOException + */ + private void processCommand(final InputStreamReader reader, + final OutputStreamWriter writer, final String command) throws IOException + { + String response = SUCCESS_RESPONSE; + + switch (command) + { + case STOP_COMMAND: + { + listening = false; + break; + } + case ALIVE_COMMAND: + { + break; + } + default: + { + response = ERROR_RESPONSE; + System.err.println("ccserver: unknown command " + command); + } + } + + // acknowledge command + writer.append(response); + writer.flush(); + } + + /** + * Initialize properties from config file. + * Validate the properties. + * + * @return true if the properties are valid, false otherwise. + * @throws IOException + */ + private boolean initializeProperties() throws IOException + { + readProperties(); + + host = config.getProperty(HOST_KEY, DEFAULT_HOST); + dataPort = getIntegerProperty(DATA_PORT_KEY, DEFAULT_DATA_PORT); + commandPort = getIntegerProperty(COMMAND_PORT_KEY, DEFAULT_COMMAND_PORT); + policyFilePort = getIntegerProperty(POLICY_FILE_PORT_KEY, DEFAULT_POLICY_FILE_PORT); + + // get absolute path of preloadSWF. + if (!initializePreloadSWF()) + return false; + + return true; + } + + /** + * Initialize the preloadSWF value. + * + * @return true if value, false otherwise. + * @throws UnsupportedEncodingException + */ + private boolean initializePreloadSWF() throws UnsupportedEncodingException + { + // if the path of the preload SWF is not configured, then try to locate + // it in the same directory as the jar containing this class. + preloadSWFPath = config.getProperty(PRELOAD_SWF_KEY, DEFAULT_PRELOAD_SWF); + File preloadSWFFile = new File(preloadSWFPath); + if (!preloadSWFFile.exists()) + { + URL preloadSWFURL = getClass().getClassLoader().getResource(preloadSWFPath); + if (preloadSWFURL != null) + { + preloadSWFPath = URLDecoder.decode(preloadSWFURL.getPath(), "UTF-8"); + preloadSWFFile = new File(preloadSWFPath); + } + + if (!preloadSWFFile.exists()) + { + System.out.println("preloadSWF not found: " + preloadSWFPath); + return false; + } + } + + preloadSWFPath = preloadSWFFile.getAbsolutePath(); + return true; + } + + /** + * Handle NumberFormatExeptions values in the configuration file. + * + * @param key + * @param defaultValue + * @return integer value of a configuration value. + */ + private int getIntegerProperty(String key, int defaultValue) + { + String value = config.getProperty(key); + int result = defaultValue; + + try + { + result = Integer.valueOf(value); + } + catch (NumberFormatException e) + { + // ignore, result is already set to defualt value + } + + return result; + } + + /** + * Send command to the command port to stop the server. + * + * @throws IOException + */ + public void stop() throws IOException + { + if (!isAlive()) + { + System.out.println("Apache Flex Code Coverage Server not running"); + return; + } + + // connect to the server and send a command + sendCommand(STOP_COMMAND); + } + + /** + * Read properties from the config.properties file. + * + * @throws IOException + */ + private void readProperties() throws IOException + { + try (InputStream inputStream = getClass().getClassLoader(). + getResourceAsStream("ccserver.properties")) + { + if (inputStream != null) + config.load(inputStream); + } + } + + /** + * Update the user's mm.cfg file to either add or remove the preloadSWF + * key. + * + * @param addPreloadSWF If true add "preloadSWF=" to the user's mm.cfg. + * @throws IOException + */ + private void updateMMCFG(final boolean addPreloadSWF) throws IOException + { + // open mm.cfg + String filename = config.getProperty(MM_CFG_PATH, + System.getProperty("user.home") + "/mm.cfg"); + + // read mm.cfg + List<String> lines = new ArrayList<String>(); + try (Reader fileReader = new FileReader(filename); + BufferedReader bufferedReader = new BufferedReader(fileReader)) + { + String line = null; + while ((line = bufferedReader.readLine()) != null) + { + // if found a preloadSWF line then don't write it in order to + // remove it. If we are adding the line we will append it later. + if (!(line.startsWith(PRELOAD_SWF_KEY + "="))) + { + lines.add(line); + } + } + + // if adding the preloadSWF key, append the preloadSWF property + if (addPreloadSWF) + { + StringBuilder preloadSWF = new StringBuilder(PRELOAD_SWF_KEY); + preloadSWF.append("="); + preloadSWF.append(preloadSWFPath); + preloadSWF.append("?host="); + preloadSWF.append(host); + preloadSWF.append("&dataPort="); + preloadSWF.append(dataPort); + preloadSWF.append("&policyFilePort="); + preloadSWF.append(policyFilePort); + lines.add(preloadSWF.toString()); + } + } + catch (FileNotFoundException e) + { + System.err.println("Unable to open mm.cfg. Create the file in the user home directory or specify the location by setting the mmCfgPath property in ccserver.properties."); + e.printStackTrace(); + return; + } + + // write mm.cfg + try (FileWriter fileWriter = new FileWriter(filename); + BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) + { + for (String line : lines) + { + bufferedWriter.write(line); + bufferedWriter.newLine(); + } + } + + } + + /** + * Send a command and get the response. + * + * @param command + * @return A String containing the response. If there is no response an + * empty string will be returned. + * @throws IOException + */ + private String sendCommand(String command) throws IOException + { + String result = ""; + char[] cbuf = new char[512]; + + try (Socket socket = new Socket(host, commandPort); + InputStreamReader reader = new InputStreamReader(socket.getInputStream()); + PrintWriter writer = new PrintWriter(socket.getOutputStream())) + { + // send command + writer.print(command); + writer.flush(); + + // read response + int charsRead = reader.read(cbuf); + if (charsRead != -1) + result = String.valueOf(cbuf, 0, charsRead); + } + + return result; + } + + /** + * Test if the server is already running. + * + * @return true if the server is running, false otherwise. + * @throws IOException + */ + private boolean isAlive() throws IOException + { + try + { + String result = sendCommand(ALIVE_COMMAND); + if (result.length() > 0) + return true; + + return false; + } + catch (ConnectException e) + { + // server not running so connection failed. + return false; + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/5077c457/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketAccepter.java ---------------------------------------------------------------------- diff --git a/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketAccepter.java b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketAccepter.java new file mode 100755 index 0000000..1de9992 --- /dev/null +++ b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketAccepter.java @@ -0,0 +1,174 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.flex.tools.codecoverage.server; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * Thread to accept requests to connections to the data port. + * When a connection is made an instance of the DataSocketThread is created to + * read data from the socket. + * + */ +public class DataSocketAccepter implements Runnable +{ + + private static final String filenameTemplate = "ccdata_{0}.txt"; + + private ServerSocket socket; + private BufferedWriter fileWriter; + private Thread dataSocketReader; + private volatile boolean listening = true; + private final File dataDirectory; + private int fileCount = 0; + private Socket currentSocket; + private final String host; + private final int dataPort; + + /** + * Constructor. + * + * @param host The host of the dataPort. + * @param dataPort The data port to service. + * @param dataDirectory The directory where the data files are stored. + * Each new connection results in a new file created in this directory. + */ + public DataSocketAccepter(final String host, final int dataPort, + final File dataDirectory) + { + + if (dataDirectory == null) + throw new NullPointerException("dataDirectory may not be null"); + + this.host = host; + this.dataPort = dataPort; + this.dataDirectory = dataDirectory; + } + + /** + * This thread will block waiting on a connect to the data port. Once a + * connection has been made an instance of DataSocketThread is run to read + * the data on the port and this thread waits for the next connection. + * Only one instance of the DataSocketThread is allowed. Before a new instance + * is created the current one is closed. + */ + @Override + public void run() + { + try + { + socket = new ServerSocket(dataPort); + + while (listening) + { + Socket newSocket = socket.accept(); + + closeResources(); + currentSocket = newSocket; + + if (!listening) + break; + + String filename = filenameTemplate.replace("{0}", String.valueOf(fileCount++)); + File file = new File(dataDirectory, filename); + System.out.println("saving trace data to " + file.getAbsolutePath()); + fileWriter = new BufferedWriter(new FileWriter(file)); + dataSocketReader = new Thread(new DataSocketReader(newSocket, fileWriter)); + dataSocketReader.start(); + } + } + catch (IOException e) + { + e.printStackTrace(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + finally + { + if (currentSocket != null) + { + try + { + currentSocket.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + + if (fileWriter != null) + { + try + { + fileWriter.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + } + + /** + * Close this thread. + * + * @throws IOException + * @throws InterruptedException + */ + public void close() throws IOException + { + // connect to socket to unblock the accept call + listening = false; + Socket socket = new Socket(host, dataPort); + socket.close(); + } + + /** + * Close the resources used by data socket thread. + * @throws InterruptedException + * @throws IOException + */ + private void closeResources() throws InterruptedException, IOException + { + if (dataSocketReader != null) + { + dataSocketReader.interrupt(); + dataSocketReader.join(); + dataSocketReader = null; + } + + if (currentSocket != null) + currentSocket.close(); + + if (fileWriter != null) + { + fileWriter.close(); + fileWriter = null; + } + } +} http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/5077c457/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketReader.java ---------------------------------------------------------------------- diff --git a/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketReader.java b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketReader.java new file mode 100755 index 0000000..6a15168 --- /dev/null +++ b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/DataSocketReader.java @@ -0,0 +1,88 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.flex.tools.codecoverage.server; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; + +/** + * Thread to read trace data from the Flex client. + * All data read from the socket is written directly to the writer + * with no processing. + * + */ +public class DataSocketReader implements Runnable +{ + private Socket socket; + private BufferedWriter fileWriter; + + /** + * Constructor. + * + * @param socket The socket to read from. + * @param fileWriter The writer to write the data to. + */ + public DataSocketReader(final Socket socket, final BufferedWriter fileWriter) + { + this.socket = socket; + this.fileWriter = fileWriter; + } + + /** + * Read data from the socket and write it the specified file until + * we are interrupted. + */ + @Override + public void run() + { + // listen for data + final char[] cbuf = new char[512 * 1024]; + + try (BufferedReader in = new BufferedReader( + new InputStreamReader( + socket.getInputStream()), 512 * 1024)) + { + while (!Thread.interrupted() && !socket.isClosed()) + { + int charsRead = in.read(cbuf); + if (charsRead > 0) + { + String buf = String.valueOf(cbuf, 0, charsRead); + fileWriter.write(buf); + } + else + { + Thread.sleep(1000); + } + } + } + catch (IOException e) + { + e.printStackTrace(); + } + catch (InterruptedException e) + { + // This happens when we are interrupted while sleeping. + } + } +} http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/5077c457/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/PolicyFileServer.java ---------------------------------------------------------------------- diff --git a/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/PolicyFileServer.java b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/PolicyFileServer.java new file mode 100755 index 0000000..117249e --- /dev/null +++ b/CodeCoverage/JavaServer/java/src/org/apache/flex/tools/codecoverage/server/PolicyFileServer.java @@ -0,0 +1,167 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.flex.tools.codecoverage.server; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * Thread to serve a policy file to the Flash Player to allow the Flash + * client to connect to the data port. + * + */ +public class PolicyFileServer implements Runnable +{ + /** + * Request sent by the Flash Player requesting the policy file. + */ + private static final String EXPECTED_REQUEST = "<policy-file-request/>"; + + /** + * Template of the policy file. Variables in brackets are replaced with + * the actual values. + */ + private static final String POLICY_FILE = "<?xml version=\"1.0\"?>" + + "<!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">" + + "<cross-domain-policy>" + + " <allow-access-from domain=\"{host}\" to-ports=\"{dataPort}\" />" + + "</cross-domain-policy>"; + + private final String host; + private final int dataPort; + private final int policyFilePort; + private boolean listening = true; + + // cached policy file create from the template. + private String policyFile; + + /** + * + * @param host + * @param dataPort + * @param policyFilePort + */ + public PolicyFileServer(final String host, final int dataPort, + final int policyFilePort) + { + this.host = host; + this.dataPort = dataPort; + this.policyFilePort = policyFilePort; + + initializePolicyFile(); + } + + /** + * Wait for a connection on the policy file port. When a connection is received + * reply with a policy file if the Flash Player is requesting. + */ + @Override + public void run() + { + ServerSocket serverSocket = null; + + try + { + // accept connections and return an in-memory policy file. + serverSocket = new ServerSocket(policyFilePort); + + while (listening) + { + try (Socket socket = serverSocket.accept()) + { + if (!listening) + break; + + writePolicyFile(socket); + } + } + } + catch (IOException e) + { + e.printStackTrace(); + } + finally + { + if (serverSocket != null) + { + try + { + serverSocket.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + } + } + + /** + * Create the policy file from the template. + */ + private void initializePolicyFile() + { + policyFile = POLICY_FILE.replace("{host}", host); + policyFile = policyFile.replace("{dataPort}", Integer.toString(dataPort)); + } + + /** + * Write the in-memory policy file to the socket. + * + * @param socket Socket to write security policy file to. + */ + private void writePolicyFile(final Socket socket) + { + char[] cbuf = new char[64]; + + try (InputStreamReader reader = new InputStreamReader(socket.getInputStream()); + OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream())) + { + int result = reader.read(cbuf); + if (result > 0 && EXPECTED_REQUEST.equals(cbuf)) + { + writer.write(policyFile); + } + } catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * Close the resources held by this thread. + * + * @throws IOException + * @throws UnknownHostException + * @throws InterruptedException + */ + public void close() throws UnknownHostException, IOException, InterruptedException + { + // connect to socket to unblock the accept call + listening = false; + final Socket socket = new Socket(host, policyFilePort); + socket.close(); + } + +}