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();
+    }
+    
+}

Reply via email to