You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2013/09/10 17:14:47 UTC

svn commit: r1521521 [3/3] - in /ace/trunk: org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/ org.apache.ace.agent/ org.apache.ace.agent/src/org/apache/ace/agent/ org.apache.ace.agent/src/org/apache/ace/agent/impl/ org.apache.ace.agent/test/or...

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackChannelImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackChannelImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackChannelImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackChannelImpl.java Tue Sep 10 15:14:46 2013
@@ -18,6 +18,8 @@
  */
 package org.apache.ace.agent.impl;
 
+import static org.apache.ace.agent.impl.ConnectionUtil.*;
+
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.EOFException;
@@ -47,6 +49,7 @@ import org.apache.ace.agent.ConnectionHa
 import org.apache.ace.agent.DiscoveryHandler;
 import org.apache.ace.agent.FeedbackChannel;
 import org.apache.ace.agent.IdentificationHandler;
+import org.apache.ace.agent.LoggingHandler;
 import org.apache.ace.agent.RetryAfterException;
 import org.apache.ace.log.LogDescriptor;
 import org.apache.ace.log.LogEvent;
@@ -61,13 +64,231 @@ import org.apache.ace.range.SortedRangeS
 // TODO: test(coverage)<br/>
 // TODO: decouple from range/log API?
 public class FeedbackChannelImpl implements FeedbackChannel {
+    /**
+     * The general idea is to provide easy access to a file of records. It supports iterating over records both by
+     * skipping and by reading. Furthermore, files can be truncated. Most methods will make an effort to reset to the
+     * last good record in case of an error -- hence, a call to truncate after an IOException might make the store
+     * readable again.
+     */
+    static class Store {
+        private final RandomAccessFile m_store;
+        private final long m_id;
+        private long m_current;
+
+        /**
+         * Create a new File based Store.
+         * 
+         * @param store
+         *            the file to use as backend.
+         * @param id
+         *            the log id of the store
+         * @throws java.io.IOException
+         *             in case the file is not rw.
+         */
+        Store(File store, long id) throws IOException {
+            m_store = new RandomAccessFile(store, "rwd");
+            m_id = id;
+        }
+
+        /**
+         * Store the given record data as the next record.
+         * 
+         * @param entry
+         *            the data of the record to store.
+         * @throws java.io.IOException
+         *             in case of any IO error.
+         */
+        public void append(long id, byte[] entry) throws IOException {
+            long pos = m_store.getFilePointer();
+            try {
+                m_store.seek(m_store.length());
+                m_store.writeLong(id);
+                m_store.writeInt(entry.length);
+                m_store.write(entry);
+                m_store.seek(pos);
+            }
+            catch (IOException ex) {
+                handle(pos, ex);
+            }
+        }
+
+        /**
+         * Release any resources.
+         * 
+         * @throws java.io.IOException
+         *             in case of any IO error.
+         */
+        public void close() throws IOException {
+            m_store.close();
+        }
+
+        /**
+         * Get the id of the current record.
+         * 
+         * @return the idea of the current record.
+         */
+        public long getCurrent() throws IOException {
+            long pos = m_store.getFilePointer();
+            if (m_store.length() == 0) {
+                return 0;
+            }
+            long result = 0;
+            try {
+                m_store.seek(m_current);
+                result = readCurrentID();
+                m_store.seek(pos);
+            }
+            catch (IOException ex) {
+                handle(pos, ex);
+            }
+            return result;
+        }
+
+        /**
+         * Get the log id of this store.
+         * 
+         * @return the log id of this store.
+         */
+        public long getId() {
+            return m_id;
+        }
+
+        /**
+         * Determine whether there are any records left based on the current postion.
+         * 
+         * @return <code>true</code> if there are still records to be read.
+         * @throws java.io.IOException
+         *             in case of an IO error.
+         */
+        public boolean hasNext() throws IOException {
+            return m_store.getFilePointer() < m_store.length();
+        }
+
+        /**
+         * Make sure the store is readable. As a result, the store is at the end of the records.
+         * 
+         * @throws java.io.IOException
+         *             in case of any IO error.
+         */
+        public void init() throws IOException {
+            reset();
+            try {
+                while (true) {
+                    skip();
+                }
+            }
+            catch (EOFException ex) {
+                // done
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public byte[] read() throws IOException {
+            long pos = m_store.getFilePointer();
+            try {
+                if (pos < m_store.length()) {
+                    long current = m_store.getFilePointer();
+                    long id = m_store.readLong();
+                    int next = m_store.readInt();
+                    byte[] entry = new byte[next];
+                    m_store.readFully(entry);
+                    m_current = current;
+                    return entry;
+                }
+            }
+            catch (IOException ex) {
+                handle(pos, ex);
+            }
+            return null;
+        }
+
+        public long readCurrentID() throws IOException {
+            long pos = m_store.getFilePointer();
+            try {
+                if (pos < m_store.length()) {
+                    long id = m_store.readLong();
+                    m_store.seek(pos);
+                    return id;
+                }
+            }
+            catch (IOException ex) {
+                handle(pos, ex);
+            }
+            return -1;
+        }
+
+        /**
+         * Reset the store to the beginning of the records
+         * 
+         * @throws java.io.IOException
+         *             in case of an IO error.
+         */
+        public void reset() throws IOException {
+            m_store.seek(0);
+            m_current = 0;
+        }
+
+        /**
+         * Skip the next record if there is any.
+         * 
+         * @throws java.io.IOException
+         *             in case of any IO error or if there is no record left.
+         */
+        @SuppressWarnings("unused")
+        public void skip() throws IOException {
+            long pos = m_store.getFilePointer();
+            try {
+                long id = m_store.readLong();
+                int next = m_store.readInt();
+                if (m_store.length() < next + m_store.getFilePointer()) {
+                    throw new IOException("Unexpected end of file");
+                }
+                m_store.seek(m_store.getFilePointer() + next);
+                m_current = pos;
+                pos = m_store.getFilePointer();
+            }
+            catch (IOException ex) {
+                handle(pos, ex);
+            }
+        }
+
+        /**
+         * Try to truncate the store at the current record.
+         * 
+         * @throws java.io.IOException
+         *             in case of any IO error.
+         */
+        public void truncate() throws IOException {
+            m_store.setLength(m_store.getFilePointer());
+        }
+
+        private void handle(long pos, IOException exception) throws IOException {
+            try {
+                m_store.seek(pos);
+            }
+            catch (IOException ex) {
+                // m_log.log(LogService.LOG_WARNING, "Exception during seek!", ex);
+            }
+            throw exception;
+        }
+    }
 
     private static final String DIRECTORY_NAME = "feedback";
     private static final String COMMAND_QUERY = "query";
     private static final String COMMAND_SEND = "send";
     private static final String PARAMETER_TARGETID = "tid";
+
     private static final String PARAMETER_LOGID = "logid";
 
+    // bridging to log api
+    private static Dictionary<String, String> mapToDictionary(Map<String, String> map) {
+        Dictionary<String, String> dictionary = new Hashtable<String, String>();
+        for (Entry<String, String> entry : map.entrySet()) {
+            dictionary.put(entry.getKey(), entry.getValue());
+        }
+        return dictionary;
+    }
+
     private final AgentContext m_agentContext;
     private final String m_name;
     private final File m_baseDir;
@@ -79,160 +300,104 @@ public class FeedbackChannelImpl impleme
     };
 
     private Store m_store = null;
+
     private long m_highest;
 
     public FeedbackChannelImpl(AgentContext agentContext, String name) throws IOException {
         m_agentContext = agentContext;
         m_name = name;
         m_baseDir = new File(m_agentContext.getWorkDir(), DIRECTORY_NAME);
-        if (!m_baseDir.isDirectory() && !m_baseDir.mkdirs())
+        if (!m_baseDir.isDirectory() && !m_baseDir.mkdirs()) {
             throw new IllegalArgumentException("Need valid dir");
+        }
         initStore();
     }
 
+    public void closeStore() throws IOException {
+        Store store;
+        synchronized (m_store) {
+            store = m_store;
+        }
+        store.close();
+        m_store = null;
+    }
+
     @Override
     public synchronized void sendFeedback() throws RetryAfterException, IOException {
         String identification = getIdentification();
         URL serverURL = getServerURL();
+
         if (identification == null || serverURL == null) {
+            logWarning("No identification or server URL present, cannot send feedback!");
             return;
         }
+
+        ConnectionHandler connectionHandler = getConnectionHandler();
         URLConnection sendConnection = null;
         Writer writer = null;
+
         try {
             URL sendURL = new URL(serverURL, m_name + "/" + COMMAND_SEND);
-            sendConnection = getConnectionHandler().getConnection(sendURL);
+
+            sendConnection = connectionHandler.getConnection(sendURL);
             sendConnection.setDoOutput(true);
             if (sendConnection instanceof HttpURLConnection) {
                 ((HttpURLConnection) sendConnection).setChunkedStreamingMode(8192);
             }
+
             writer = new BufferedWriter(new OutputStreamWriter(sendConnection.getOutputStream()));
             SortedSet<Long> storeIDs = getStoreIDs();
             for (Long storeID : storeIDs) {
                 URL queryURL = new URL(serverURL, m_name + "/" + COMMAND_QUERY + "?" + PARAMETER_TARGETID + "=" + identification + "&" + PARAMETER_LOGID + "=" + storeID);
-                URLConnection queryConnection = getConnectionHandler().getConnection(queryURL);
-                synchronizeStore(storeID, queryConnection.getInputStream(), writer);
+                URLConnection queryConnection = connectionHandler.getConnection(queryURL);
+                try {
+                    synchronizeStore(storeID, queryConnection.getInputStream(), writer);
+                }
+                finally {
+                    close(queryConnection);
+                }
             }
             writer.flush();
+
             ConnectionUtil.checkConnectionResponse(sendConnection);
             sendConnection.getContent();
         }
         finally {
-            if (writer != null)
-                writer.close();
-            if (sendConnection instanceof HttpURLConnection)
-                ((HttpURLConnection) sendConnection).disconnect();
+            closeSilently(writer);
+            close(sendConnection);
         }
     }
 
     @Override
-    public synchronized void write(int type, Map<String, String> properties) throws IOException {
-        try {
-            LogEvent result = new LogEvent(null, m_store.getId(), getNextEventID(), System.currentTimeMillis(), type, mapToDictionary(properties));
-            m_store.append(result.getID(), result.toRepresentation().getBytes());
-        }
-        catch (IOException ex) {
-            handleException(m_store, ex);
+    public void write(int type, Map<String, String> properties) throws IOException {
+        synchronized (m_store) {
+            try {
+                LogEvent result = new LogEvent(null, m_store.getId(), getNextEventID(), System.currentTimeMillis(), type, mapToDictionary(properties));
+                m_store.append(result.getID(), result.toRepresentation().getBytes());
+            }
+            catch (IOException ex) {
+                handleException(m_store, ex);
+            }
         }
     }
 
-    // TODO Is this called?
-    public synchronized void closeStore() throws IOException {
-        m_store.close();
-        m_store = null;
-    }
-
-    private void initStore() throws IOException {
-        SortedSet<Long> storeIDs = getStoreIDs();
-        if (storeIDs.isEmpty()) {
-            m_store = newFeedbackStore();
-        }
-        else {
-            m_store = createStore(storeIDs.last());
+    private void closeIfNeeded(Store store) {
+        if (store != m_store) {
             try {
-                m_store.init();
+                store.close();
             }
             catch (IOException ex) {
-                handleException(m_store, ex);
+                // Not much we can do;
             }
         }
     }
 
-    private void synchronizeStore(long storeID, InputStream queryInput, Writer sendWriter) throws IOException {
-        long highestLocal = getHighestEventID(storeID);
-        if (highestLocal == 0)
-            return;
-        SortedRangeSet localRange = new SortedRangeSet("1-" + highestLocal);
-        SortedRangeSet remoteRange = getQueryDescriptor(queryInput).getRangeSet();
-        SortedRangeSet delta = remoteRange.diffDest(localRange);
-        RangeIterator rangeIterator = delta.iterator();
-        if (!rangeIterator.hasNext())
-            return;
-        String identification = getIdentification();
-        long lowest = rangeIterator.next();
-        long highest = delta.getHigh();
-        if (lowest <= highest) {
-            List<LogEvent> events = getEvents(storeID, lowest, highestLocal > highest ? highest : highestLocal);
-            Iterator<LogEvent> iter = events.iterator();
-            while (iter.hasNext()) {
-                LogEvent current = (LogEvent) iter.next();
-                while ((current.getID() > lowest) && rangeIterator.hasNext()) {
-                    lowest = rangeIterator.next();
-                }
-                if (current.getID() == lowest) {
-                    LogEvent event = new LogEvent(identification, current);
-                    sendWriter.write(event.toRepresentation());
-                    sendWriter.write("\n");
-                }
-            }
-        }
-    }
-
-    private LogDescriptor getQueryDescriptor(InputStream queryInput) throws IOException {
-        BufferedReader queryReader = null;
-        try {
-            queryReader = new BufferedReader(new InputStreamReader(queryInput));
-            String rangeString = queryReader.readLine();
-            if (rangeString == null) {
-                throw new IOException("Could not construct LogDescriptor from stream because stream is empty");
-            }
-            try {
-                return new LogDescriptor(rangeString);
-            }
-            catch (IllegalArgumentException e) {
-                throw new IOException("Could not determine highest remote event id, received malformed event range (" + rangeString + ")");
-            }
-        }
-        finally {
-            if (queryReader != null) {
-                try {
-                    queryReader.close();
-                }
-                catch (Exception ex) {
-                    // not much we can do
-                }
-            }
-        }
-    }
-
-    private Store newFeedbackStore() throws IOException {
-        long storeId = System.currentTimeMillis();
-        while (!(new File(m_baseDir, getStoreName(storeId))).createNewFile()) {
-            storeId++;
-        }
-        return new Store(new File(m_baseDir, getStoreName(storeId)), storeId);
-    }
-
     private Store createStore(long storeId) throws IOException {
         return new Store(new File(m_baseDir, getStoreName(storeId)), storeId);
     }
 
-    private String getStoreName(long storeId) {
-        return m_name + "-" + storeId;
-    }
-
-    private long getStoreId(String storeName) {
-        return Long.parseLong(storeName.replace(m_name + "-", ""));
+    private ConnectionHandler getConnectionHandler() {
+        return m_agentContext.getHandler(ConnectionHandler.class);
     }
 
     private List<LogEvent> getEvents(long storeID, long fromEventID, long toEventID) throws IOException {
@@ -261,47 +426,6 @@ public class FeedbackChannelImpl impleme
         return result;
     }
 
-    private void handleException(Store store, Exception exception) throws IOException {
-        // System.err.println(LogService.LOG_WARNING, "Exception accessing the log: "
-        // + store.getId(), exception);
-        if (store == m_store)
-            m_store = newFeedbackStore();
-
-        try {
-            store.truncate();
-        }
-        catch (IOException ex) {
-            // m_log.log(LogService.LOG_WARNING, "Exception during truncate: "
-            // + store.getId(), ex);
-        }
-        try {
-            store.close();
-        }
-        catch (IOException ex) {
-            // Not much we can do
-        }
-        if (exception instanceof IOException) {
-            throw (IOException) exception;
-        }
-        throw new IOException("Unable to read log entry: "
-            + exception.getMessage());
-    }
-
-    private File[] getStoreFiles() throws IOException {
-        File[] files = (File[]) m_baseDir.listFiles(m_fileFilter);
-        if (files == null)
-            throw new IOException("Unable to list store files in " + m_baseDir.getAbsolutePath());
-        return files;
-    }
-
-    private SortedSet<Long> getStoreIDs() throws IOException {
-        File[] files = getStoreFiles();
-        SortedSet<Long> storeIDs = new TreeSet<Long>();
-        for (int i = 0; i < files.length; i++)
-            storeIDs.add(getStoreId(files[i].getName()));
-        return storeIDs;
-    }
-
     private long getHighestEventID(long storeID) throws IOException {
         Store store = getStore(storeID);
         try {
@@ -322,17 +446,49 @@ public class FeedbackChannelImpl impleme
         return -1;
     }
 
-    private void closeIfNeeded(Store store) {
-        if (store != m_store) {
+    private String getIdentification() {
+        return m_agentContext.getHandler(IdentificationHandler.class).getAgentId();
+    }
+
+    private LoggingHandler getLoggingHandler() {
+        return m_agentContext.getHandler(LoggingHandler.class);
+    }
+
+    private long getNextEventID() throws IOException {
+        return (m_highest = getHighestEventID(m_store.m_id) + 1);
+    }
+
+    private LogDescriptor getQueryDescriptor(InputStream queryInput) throws IOException {
+        BufferedReader queryReader = null;
+        try {
+            queryReader = new BufferedReader(new InputStreamReader(queryInput));
+            String rangeString = queryReader.readLine();
+            if (rangeString == null) {
+                throw new IOException("Could not construct LogDescriptor from stream because stream is empty");
+            }
             try {
-                store.close();
+                return new LogDescriptor(rangeString);
             }
-            catch (IOException ex) {
-                // Not much we can do;
+            catch (IllegalArgumentException e) {
+                throw new IOException("Could not determine highest remote event id, received malformed event range (" + rangeString + ")");
+            }
+        }
+        finally {
+            if (queryReader != null) {
+                try {
+                    queryReader.close();
+                }
+                catch (Exception ex) {
+                    // not much we can do
+                }
             }
         }
     }
 
+    private URL getServerURL() {
+        return m_agentContext.getHandler(DiscoveryHandler.class).getServerUrl();
+    }
+
     private Store getStore(long storeID) throws IOException {
         if (m_store.getId() == storeID) {
             return m_store;
@@ -340,225 +496,120 @@ public class FeedbackChannelImpl impleme
         return createStore(storeID);
     }
 
-    private long getNextEventID() throws IOException {
-        return (m_highest = getHighestEventID(m_store.m_id) + 1);
-    }
-
-    private ConnectionHandler getConnectionHandler() {
-        return m_agentContext.getHandler(ConnectionHandler.class);
+    private File[] getStoreFiles() throws IOException {
+        File[] files = (File[]) m_baseDir.listFiles(m_fileFilter);
+        if (files == null) {
+            throw new IOException("Unable to list store files in " + m_baseDir.getAbsolutePath());
+        }
+        return files;
     }
 
-    private String getIdentification() {
-        return m_agentContext.getHandler(IdentificationHandler.class).getAgentId();
+    private long getStoreId(String storeName) {
+        return Long.parseLong(storeName.replace(m_name + "-", ""));
     }
 
-    private URL getServerURL() {
-        return m_agentContext.getHandler(DiscoveryHandler.class).getServerUrl();
+    private SortedSet<Long> getStoreIDs() throws IOException {
+        File[] files = getStoreFiles();
+        SortedSet<Long> storeIDs = new TreeSet<Long>();
+        for (int i = 0; i < files.length; i++) {
+            storeIDs.add(getStoreId(files[i].getName()));
+        }
+        return storeIDs;
     }
 
-    // bridging to log api
-    private static Dictionary<String, String> mapToDictionary(Map<String, String> map) {
-        Dictionary<String, String> dictionary = new Hashtable<String, String>();
-        for (Entry<String, String> entry : map.entrySet()) {
-            dictionary.put(entry.getKey(), entry.getValue());
-        }
-        return dictionary;
+    private String getStoreName(long storeId) {
+        return m_name + "-" + storeId;
     }
 
-    /**
-     * The general idea is to provide easy access to a file of records. It supports iterating over records both by
-     * skipping and by reading. Furthermore, files can be truncated. Most methods will make an effort to reset to the
-     * last good record in case of an error -- hence, a call to truncate after an IOException might make the store
-     * readable again.
-     */
-    static class Store {
-        private final RandomAccessFile m_store;
-        private final long m_id;
-        private long m_current;
+    private void handleException(Store store, Exception exception) throws IOException {
+        logError("Exception caught while accessing feedback channel store #%d", exception, store.getId());
 
-        /**
-         * Create a new File based Store.
-         * 
-         * @param store the file to use as backend.
-         * @param id the log id of the store
-         * @throws java.io.IOException in case the file is not rw.
-         */
-        Store(File store, long id) throws IOException {
-            m_store = new RandomAccessFile(store, "rwd");
-            m_id = id;
+        if (store == m_store) {
+            m_store = newFeedbackStore();
         }
-
-        /**
-         * Get the id of the current record.
-         * 
-         * @return the idea of the current record.
-         */
-        public long getCurrent() throws IOException {
-            long pos = m_store.getFilePointer();
-            if (m_store.length() == 0) {
-                return 0;
-            }
-            long result = 0;
-            try {
-                m_store.seek(m_current);
-                result = readCurrentID();
-                m_store.seek(pos);
-            }
-            catch (IOException ex) {
-                handle(pos, ex);
-            }
-            return result;
+        try {
+            store.truncate();
         }
-
-        /**
-         * Get the log id of this store.
-         * 
-         * @return the log id of this store.
-         */
-        public long getId() {
-            return m_id;
+        catch (IOException ex) {
+            logError("Exception caught while truncating feedback channel store #%d", ex, store.getId());
         }
 
-        /**
-         * Reset the store to the beginning of the records
-         * 
-         * @throws java.io.IOException in case of an IO error.
-         */
-        public void reset() throws IOException {
-            m_store.seek(0);
-            m_current = 0;
+        try {
+            store.close();
         }
-
-        /**
-         * Determine whether there are any records left based on the current postion.
-         * 
-         * @return <code>true</code> if there are still records to be read.
-         * @throws java.io.IOException in case of an IO error.
-         */
-        public boolean hasNext() throws IOException {
-            return m_store.getFilePointer() < m_store.length();
+        catch (IOException ex) {
+            // Not much we can do
         }
 
-        public byte[] read() throws IOException {
-            long pos = m_store.getFilePointer();
-            try {
-                if (pos < m_store.length()) {
-                    long current = m_store.getFilePointer();
-                    long id = m_store.readLong();
-                    int next = m_store.readInt();
-                    byte[] entry = new byte[next];
-                    m_store.readFully(entry);
-                    m_current = current;
-                    return entry;
-                }
-            }
-            catch (IOException ex) {
-                handle(pos, ex);
-            }
-            return null;
+        if (exception instanceof IOException) {
+            throw (IOException) exception;
         }
 
-        public long readCurrentID() throws IOException {
-            long pos = m_store.getFilePointer();
-            try {
-                if (pos < m_store.length()) {
-                    long id = m_store.readLong();
-                    m_store.seek(pos);
-                    return id;
-                }
-            }
-            catch (IOException ex) {
-                handle(pos, ex);
-            }
-            return -1;
-        }
+        throw new IOException("Unable to read log entry: " + exception.getMessage());
+    }
 
-        /**
-         * Make sure the store is readable. As a result, the store is at the end of the records.
-         * 
-         * @throws java.io.IOException in case of any IO error.
-         */
-        public void init() throws IOException {
-            reset();
-            try {
-                while (true) {
-                    skip();
-                }
-            }
-            catch (EOFException ex) {
-                // done
-            }
+    private void initStore() throws IOException {
+        SortedSet<Long> storeIDs = getStoreIDs();
+        if (storeIDs.isEmpty()) {
+            m_store = newFeedbackStore();
         }
-
-        /**
-         * Skip the next record if there is any.
-         * 
-         * @throws java.io.IOException in case of any IO error or if there is no record left.
-         */
-        public void skip() throws IOException {
-            long pos = m_store.getFilePointer();
+        else {
+            m_store = createStore(storeIDs.last());
             try {
-                long id = m_store.readLong();
-                int next = m_store.readInt();
-                if (m_store.length() < next + m_store.getFilePointer()) {
-                    throw new IOException("Unexpected end of file");
-                }
-                m_store.seek(m_store.getFilePointer() + next);
-                m_current = pos;
-                pos = m_store.getFilePointer();
+                m_store.init();
             }
             catch (IOException ex) {
-                handle(pos, ex);
+                handleException(m_store, ex);
             }
         }
+    }
 
-        /**
-         * Store the given record data as the next record.
-         * 
-         * @param entry the data of the record to store.
-         * @throws java.io.IOException in case of any IO error.
-         */
-        public void append(long id, byte[] entry) throws IOException {
-            long pos = m_store.getFilePointer();
-            try {
-                m_store.seek(m_store.length());
-                long current = m_store.getFilePointer();
-                m_store.writeLong(id);
-                m_store.writeInt(entry.length);
-                m_store.write(entry);
-                m_store.seek(pos);
-            }
-            catch (IOException ex) {
-                handle(pos, ex);
-            }
-        }
+    private void logError(String msg, Exception cause, Object... args) {
+        getLoggingHandler().logError("feedbackChannel(" + m_name + ")", msg, cause, args);
+    }
 
-        /**
-         * Try to truncate the store at the current record.
-         * 
-         * @throws java.io.IOException in case of any IO error.
-         */
-        public void truncate() throws IOException {
-            m_store.setLength(m_store.getFilePointer());
-        }
+    private void logWarning(String msg, Object... args) {
+        getLoggingHandler().logWarning("feedbackChannel(" + m_name + ")", msg, null, args);
+    }
 
-        /**
-         * Release any resources.
-         * 
-         * @throws java.io.IOException in case of any IO error.
-         */
-        public void close() throws IOException {
-            m_store.close();
+    private Store newFeedbackStore() throws IOException {
+        long storeId = System.currentTimeMillis();
+        // XXX this can fail in case of high concurrent situations!
+        while (!(new File(m_baseDir, getStoreName(storeId))).createNewFile()) {
+            storeId++;
         }
+        return new Store(new File(m_baseDir, getStoreName(storeId)), storeId);
+    }
 
-        private void handle(long pos, IOException exception) throws IOException {
-            try {
-                m_store.seek(pos);
-            }
-            catch (IOException ex) {
-                // m_log.log(LogService.LOG_WARNING, "Exception during seek!", ex);
+    private void synchronizeStore(long storeID, InputStream queryInput, Writer sendWriter) throws IOException {
+        long highestLocal = getHighestEventID(storeID);
+        if (highestLocal == 0) {
+            return;
+        }
+        SortedRangeSet localRange = new SortedRangeSet("1-" + highestLocal);
+        SortedRangeSet remoteRange = getQueryDescriptor(queryInput).getRangeSet();
+        SortedRangeSet delta = remoteRange.diffDest(localRange);
+        RangeIterator rangeIterator = delta.iterator();
+        if (!rangeIterator.hasNext()) {
+            return;
+        }
+        String identification = getIdentification();
+        long lowest = rangeIterator.next();
+        long highest = delta.getHigh();
+        if (lowest <= highest) {
+            List<LogEvent> events = getEvents(storeID, lowest, highestLocal > highest ? highest : highestLocal);
+            Iterator<LogEvent> iter = events.iterator();
+            while (iter.hasNext()) {
+                LogEvent current = (LogEvent) iter.next();
+                while ((current.getID() > lowest) && rangeIterator.hasNext()) {
+                    lowest = rangeIterator.next();
+                }
+                if (current.getID() == lowest) {
+                    LogEvent event = new LogEvent(identification, current);
+                    sendWriter.write(event.toRepresentation());
+                    sendWriter.write("\n");
+                }
             }
-            throw exception;
         }
     }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackHandlerImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackHandlerImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackHandlerImpl.java Tue Sep 10 15:14:46 2013
@@ -19,82 +19,90 @@
 package org.apache.ace.agent.impl;
 
 import static org.apache.ace.agent.AgentConstants.CONFIG_FEEDBACK_CHANNELS;
+import static org.apache.ace.agent.impl.InternalConstants.AGENT_CONFIG_CHANGED;
 
 import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
+import org.apache.ace.agent.EventListener;
 import org.apache.ace.agent.FeedbackChannel;
 import org.apache.ace.agent.FeedbackHandler;
 
 /**
  * Default implementation of the feedback handler.
  */
-public class FeedbackHandlerImpl extends ComponentBase implements FeedbackHandler {
-
-    private final Map<String, FeedbackChannelImpl> m_channels = new HashMap<String, FeedbackChannelImpl>();
-    private Set<String> m_channelNames;
-    private String m_channelNamesConfig;
+public class FeedbackHandlerImpl extends ComponentBase implements FeedbackHandler, EventListener {
+    private final ConcurrentMap<String, FeedbackChannelImpl> m_channels;
 
     public FeedbackHandlerImpl() {
         super("feedback");
+
+        m_channels = new ConcurrentHashMap<String, FeedbackChannelImpl>();
     }
 
     @Override
-    protected void onStart() throws Exception {
-        synchronized (m_channels) {
-            ensureChannels(); // fail fast
-        }
+    public Set<String> getChannelNames() throws IOException {
+        return m_channels.keySet();
     }
 
     @Override
-    protected void onStop() throws Exception {
-        synchronized (m_channels) {
-            clearChannels();
-        }
+    public FeedbackChannel getChannel(String name) throws IOException {
+        return m_channels.get(name);
     }
 
     @Override
-    public Set<String> getChannelNames() throws IOException {
-        synchronized (m_channels) {
-            ensureChannels();
-            return m_channelNames;
+    public void handle(String topic, Map<String, String> payload) {
+        if (AGENT_CONFIG_CHANGED.equals(topic)) {
+            String value = payload.get(CONFIG_FEEDBACK_CHANNELS);
+            if (value != null && !"".equals(value.trim())) {
+                Set<String> seen = new HashSet<String>(m_channels.keySet());
+
+                Set<String> channelNames = split(value);
+                if (channelNames.containsAll(seen) && seen.containsAll(channelNames)) {
+                    // Nothing to do...
+                    return;
+                }
+
+                for (String channelName : channelNames) {
+                    try {
+                        m_channels.putIfAbsent(channelName, new FeedbackChannelImpl(getAgentContext(), channelName));
+                        seen.remove(channelName);
+                    }
+                    catch (IOException exception) {
+                        logError("Failed to created feedback channel for '%s'", exception, channelName);
+                    }
+                }
+
+                for (String oldChannelName : seen) {
+                    FeedbackChannelImpl channel = m_channels.remove(oldChannelName);
+                    try {
+                        channel.closeStore();
+                    }
+                    catch (IOException exception) {
+                        logError("Failed to close feedback channel for '%s'", exception, oldChannelName);
+                    }
+                }
+            }
         }
     }
 
     @Override
-    public FeedbackChannel getChannel(String name) throws IOException {
-        synchronized (m_channels) {
-            ensureChannels();
-            return m_channels.get(name);
-        }
+    protected void onInit() throws Exception {
+        getEventsHandler().addListener(this);
     }
 
-    private void ensureChannels() throws IOException {
-        String channelNamesConfig = getConfigurationHandler().get(CONFIG_FEEDBACK_CHANNELS, "auditlog");
-        if (m_channelNamesConfig != null && m_channelNamesConfig.equals(channelNamesConfig)) {
-            return;
-        }
-
-        m_channelNamesConfig = channelNamesConfig;
-        m_channelNames = Collections.unmodifiableSet(getConfigurationValues(channelNamesConfig));
-        m_channels.clear();
-        for (String channelName : m_channelNames) {
-            m_channels.put(channelName, new FeedbackChannelImpl(getAgentContext(), channelName));
-        }
-    }
+    @Override
+    protected void onStop() throws Exception {
+        getEventsHandler().removeListener(this);
 
-    private void clearChannels() {
-        m_channelNamesConfig = null;
-        m_channelNames = null;
         m_channels.clear();
     }
 
-    // TODO move to util or configurationhandler
-    private static Set<String> getConfigurationValues(String value) {
+    private static Set<String> split(String value) {
         Set<String> trimmedValues = new HashSet<String>();
         if (value != null) {
             String[] rawValues = value.split(",");

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/IdentificationHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/IdentificationHandlerImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/IdentificationHandlerImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/IdentificationHandlerImpl.java Tue Sep 10 15:14:46 2013
@@ -28,16 +28,15 @@ import org.apache.ace.agent.Identificati
  * 
  */
 public class IdentificationHandlerImpl extends ComponentBase implements IdentificationHandler {
+    /** Default name to use for a new target. */
+    public static final String CONFIG_DEFAULT_AGENTID = "defaultTargetID";
 
     public IdentificationHandlerImpl() {
         super("identification");
     }
 
-    public static final String CONFIG_DEFAULT_AGENTID = "defaultTargetID";
-
     @Override
     public String getAgentId() {
-        String configValue = getConfigurationHandler().get(CONFIG_IDENTIFICATION_AGENTID, "defaultTargetID");
-        return configValue;
+        return getConfigurationHandler().get(CONFIG_IDENTIFICATION_AGENTID, CONFIG_DEFAULT_AGENTID);
     }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/LoggingHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/LoggingHandlerImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/LoggingHandlerImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/LoggingHandlerImpl.java Tue Sep 10 15:14:46 2013
@@ -19,73 +19,91 @@
 package org.apache.ace.agent.impl;
 
 import static org.apache.ace.agent.AgentConstants.CONFIG_LOGGING_LEVEL;
+import static org.apache.ace.agent.impl.InternalConstants.AGENT_CONFIG_CHANGED;
 
 import java.util.Date;
+import java.util.Map;
 
+import org.apache.ace.agent.EventListener;
 import org.apache.ace.agent.LoggingHandler;
 
 /**
  * Default thread-safe {@link LoggingHandler} implementation that logs messages to {@link System.out} .
  */
-public class LoggingHandlerImpl extends ComponentBase implements LoggingHandler {
+public class LoggingHandlerImpl extends ComponentBase implements LoggingHandler, EventListener {
+    private static final Levels DEFAULT = Levels.WARNING;
+    
+    private volatile Levels m_logLevel;
 
     public LoggingHandlerImpl() {
         super("logging");
+        
+        m_logLevel = DEFAULT;
+    }
+    
+    @Override
+    public void handle(String topic, Map<String, String> payload) {
+        if (AGENT_CONFIG_CHANGED.equals(topic)) {
+            String newValue = payload.get(CONFIG_LOGGING_LEVEL);
+
+            m_logLevel = fromName(newValue);
+        }
     }
 
     @Override
     public void logDebug(String component, String message, Throwable exception, Object... args) {
-        Levels level = getLogLevel();
-        if (level == Levels.DEBUG) {
-            log(Levels.DEBUG.name(), component, message, exception, args);
-        }
+        log(Levels.DEBUG, component, message, exception, args);
     }
 
     @Override
     public void logInfo(String component, String message, Throwable exception, Object... args) {
-        Levels level = getLogLevel();
-        if (level == Levels.DEBUG || level == Levels.INFO) {
-            log(Levels.INFO.name(), component, message, exception, args);
-        }
+        log(Levels.INFO, component, message, exception, args);
     }
 
     @Override
     public void logWarning(String component, String message, Throwable exception, Object... args) {
-        Levels level = getLogLevel();
-        if (level == Levels.DEBUG || level == Levels.INFO || level == Levels.WARNING) {
-            log(Levels.WARNING.name(), component, message, exception, args);
-        }
+        log(Levels.WARNING, component, message, exception, args);
     }
 
     @Override
     public void logError(String component, String message, Throwable exception, Object... args) {
-        log(Levels.ERROR.name(), component, message, exception, args);
+        log(Levels.ERROR, component, message, exception, args);
+    }
+    
+    @Override
+    protected void onInit() throws Exception {
+        getEventsHandler().addListener(this);
+    }
+    
+    @Override
+    protected void onStop() throws Exception {
+        getEventsHandler().removeListener(this);
     }
 
-    private void log(String level, String component, String message, Throwable exception, Object... args) {
+    private void log(Levels logLevel, String component, String message, Throwable exception, Object... args) {
+        if (m_logLevel.ordinal() > logLevel.ordinal()) {
+            // we're not interested at this log entry...
+            return;
+        }
         if (args.length > 0) {
             message = String.format(message, args);
         }
-        String line = String.format("[%s] %TT (%s) %s", level, new Date(), component, message);
-        System.out.println(line);
+        System.out.printf("[%s] %TT (%s) %s%n", logLevel, new Date(), component, message);
+
         if (exception != null) {
             exception.printStackTrace(System.out);
         }
     }
 
-    // TODO performance; replace with configuration events
-    private Levels getLogLevel() {
-        String config = getConfigurationHandler().get(CONFIG_LOGGING_LEVEL, Levels.INFO.name());
-        return fromName(config);
-    }
-
     private static Levels fromName(String name) {
-        name = name.toUpperCase().trim();
+        if (name == null) {
+            return DEFAULT;
+        }
         try {
             return Levels.valueOf(name.toUpperCase().trim());
         }
         catch (Exception e) {
-            return Levels.ERROR;
+            return DEFAULT;
         }
     }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/UpdateHandlerBase.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/UpdateHandlerBase.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/UpdateHandlerBase.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/UpdateHandlerBase.java Tue Sep 10 15:14:46 2013
@@ -18,6 +18,10 @@
  */
 package org.apache.ace.agent.impl;
 
+import static org.apache.ace.agent.impl.ConnectionUtil.checkConnectionResponse;
+import static org.apache.ace.agent.impl.ConnectionUtil.close;
+import static org.apache.ace.agent.impl.ConnectionUtil.closeSilently;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -45,7 +49,9 @@ public class UpdateHandlerBase extends C
         BufferedReader reader = null;
         try {
             connection = getConnection(endpoint);
-            ConnectionUtil.checkConnectionResponse(connection);
+
+            checkConnectionResponse(connection);
+
             reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
             String versionString;
             while ((versionString = reader.readLine()) != null) {
@@ -60,68 +66,47 @@ public class UpdateHandlerBase extends C
             return versions;
         }
         finally {
-            if (connection != null && connection instanceof HttpURLConnection) {
-                ((HttpURLConnection) connection).disconnect();
-            }
-            if (reader != null) {
-                reader.close();
-            }
+            closeSilently(reader);
+            close(connection);
+        }
+    }
+
+    protected DownloadHandle getDownloadHandle(URL packageURL) {
+        return getDownloadHandler().getHandle(packageURL);
+    }
+
+    protected String getIdentification() {
+        return getIdentificationHandler().getAgentId();
+    }
+
+    protected InputStream getInputStream(URL packageURL) throws IOException {
+        URLConnection urlConnection = null;
+        // TODO handle problems and retries
+        try {
+            urlConnection = getConnection(packageURL);
+            return urlConnection.getInputStream();
+        }
+        catch (IOException e) {
+            close(urlConnection);
+            throw e;
         }
     }
 
     protected long getPackageSize(URL url) throws RetryAfterException, IOException {
-        long packageSize = -1l;
         URLConnection urlConnection = null;
-        InputStream inputStream = null;
         try {
             urlConnection = url.openConnection();
             if (urlConnection instanceof HttpURLConnection) {
                 ((HttpURLConnection) urlConnection).setRequestMethod("HEAD");
             }
 
-            String dpSizeHeader = urlConnection.getHeaderField(AgentConstants.HEADER_DPSIZE);
-            if (dpSizeHeader != null) {
-                try {
-                    packageSize = Long.parseLong(dpSizeHeader);
-                }
-                catch (NumberFormatException e) {
-                    // ignore
-                }
-            }
-            return packageSize;
+            return urlConnection.getHeaderFieldLong(AgentConstants.HEADER_DPSIZE, -1L);
         }
         finally {
-            if (urlConnection != null && urlConnection instanceof HttpURLConnection) {
-                ((HttpURLConnection) urlConnection).disconnect();
-            }
-            if (inputStream != null) {
-                try {
-                    inputStream.close();
-                }
-                catch (IOException e) {
-                    // ignore
-                }
-            }
+            close(urlConnection);
         }
     }
 
-    protected InputStream getInputStream(URL packageURL) throws RetryAfterException, IOException {
-        URLConnection urlConnection = null;
-        InputStream inputStream = null;
-        // TODO handle problems and retries
-        urlConnection = getConnection(packageURL);
-        inputStream = urlConnection.getInputStream();
-        return inputStream;
-    }
-
-    protected DownloadHandle getDownloadHandle(URL packageURL) {
-        return getDownloadHandler().getHandle(packageURL);
-    }
-
-    protected String getIdentification() {
-        return getIdentificationHandler().getAgentId();
-    }
-
     protected URL getServerURL() throws RetryAfterException {
         // FIXME not sure if this is the proper place
         URL serverURL = getDiscoveryHandler().getServerUrl();

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java Tue Sep 10 15:14:46 2013
@@ -77,23 +77,23 @@ public class ConfigurationHandlerImplTes
 
     @Test
     public void testConfigSystemProps() throws Exception {
-
         String systemKey1 = AgentConstants.CONFIG_KEY_NAMESPACE + "key1";
         String systemKey2 = AgentConstants.CONFIG_KEY_NAMESPACE + "key2";
 
         System.setProperty(systemKey1, "value1");
         System.setProperty(systemKey2, "value2");
 
-        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl();
         m_agentContextImpl.stop();
-        m_agentContextImpl.setHandler(ConfigurationHandler.class, configurationHandler);
+
+        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
         m_agentContextImpl.start();
-        configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
+
+        ConfigurationHandler configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
         assertNotNull(configurationHandler.keySet());
         assertEquals(2, configurationHandler.keySet().size());
-        assertEquals(configurationHandler.get(systemKey1, "qqq"), "value1");
-        assertEquals(configurationHandler.get(systemKey2, "qqq"), "value2");
+        assertEquals(configurationHandler.get(systemKey1, "default1"), "value1");
+        assertEquals(configurationHandler.get(systemKey2, "default2"), "value2");
 
         // System props should be persisted
 
@@ -101,8 +101,10 @@ public class ConfigurationHandlerImplTes
         System.clearProperty(systemKey2);
 
         m_agentContextImpl.stop();
+
         m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
         m_agentContextImpl.start();
+
         configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
         assertNotNull(configurationHandler.keySet());

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java Tue Sep 10 15:14:46 2013
@@ -18,17 +18,13 @@
  */
 package org.apache.ace.agent.impl;
 
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.notNull;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
 import static org.testng.Assert.assertEquals;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -39,6 +35,8 @@ import javax.xml.bind.DatatypeConverter;
 import org.apache.ace.agent.AgentConstants;
 import org.apache.ace.agent.ConfigurationHandler;
 import org.apache.ace.agent.ConnectionHandler;
+import org.apache.ace.agent.ConnectionHandler.Types;
+import org.apache.ace.agent.EventsHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
 import org.apache.ace.agent.testutil.TestWebServer;
 import org.testng.annotations.AfterTest;
@@ -48,45 +46,47 @@ import org.testng.annotations.Test;
 /**
  * Testing {@link ConnectionHandlerImpl},
  */
-// TODO test CLIENT_CERT
 public class ConnectionHandlerImplTest extends BaseAgentTest {
 
     static class BasicAuthServlet extends HttpServlet {
-
         private static final long serialVersionUID = 1L;
 
         private final String m_authHeader;
 
         public BasicAuthServlet(String username, String password) {
-            m_authHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
+            m_authHeader = "Basic ".concat(DatatypeConverter.printBase64Binary((username + ":" + password).getBytes()));
         }
 
         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             String authHeader = req.getHeader("Authorization");
-            if (authHeader == null || !authHeader.equals(m_authHeader))
+            if (authHeader == null || !authHeader.equals(m_authHeader)) {
                 resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Requires Basic Auth");
-            resp.setStatus(HttpServletResponse.SC_OK);
+            } else {
+                resp.setStatus(HttpServletResponse.SC_OK);
+            }
         }
     }
 
+    private static final int PORT = 8880;
+    private static final String USERNAME = "john.doe";
+    private static final String PASSWORD = "secret";
+
     private TestWebServer m_webServer;
-    private String m_user = "Mickey";
-    private String m_pass = "Mantle";
     private URL m_basicAuthURL;
-
     private AgentContextImpl m_agentContext;
 
     @BeforeTest
     public void setUpOnceAgain() throws Exception {
+        m_basicAuthURL = new URL("http://localhost:" + PORT + "/basicauth");
 
-        int port = 8880;
-        m_basicAuthURL = new URL("http://localhost:" + port + "/basicauth");
-        m_webServer = new TestWebServer(port, "/", "generated");
-        m_webServer.addServlet(new BasicAuthServlet(m_user, m_pass), "/basicauth/*");
+        m_webServer = new TestWebServer(PORT, "/", "generated");
+        m_webServer.addServlet(new BasicAuthServlet(USERNAME, PASSWORD), "/basicauth/*");
         m_webServer.start();
 
         m_agentContext = mockAgentContext();
+        m_agentContext.setHandler(EventsHandler.class, new EventsHandlerImpl(mockBundleContext()));
+        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
         m_agentContext.setHandler(ConnectionHandler.class, new ConnectionHandlerImpl());
 
         replayTestMocks();
@@ -103,24 +103,30 @@ public class ConnectionHandlerImplTest e
 
     @Test
     public void testBasicAuthFORBIDDEN() throws Exception {
+        Map<String, String> props = new HashMap<String, String>();
+        props.put(AgentConstants.CONFIG_CONNECTION_AUTHTYPE, Types.NONE.name());
+
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
+        configurationHandler.putAll(props);
+
         ConnectionHandler connectionHandler = m_agentContext.getHandler(ConnectionHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(notNull(String.class), anyObject(String.class))).andReturn(null).anyTimes();
-        replay(configurationHandler);
         HttpURLConnection connection = (HttpURLConnection) connectionHandler.getConnection(m_basicAuthURL);
+
         assertEquals(connection.getResponseCode(), HttpServletResponse.SC_FORBIDDEN);
     }
 
     @Test
     public void testBasicAuthOK() throws Exception {
+        Map<String, String> props = new HashMap<String, String>();
+        props.put(AgentConstants.CONFIG_CONNECTION_AUTHTYPE, Types.BASIC.name());
+        props.put(AgentConstants.CONFIG_CONNECTION_USERNAME, USERNAME);
+        props.put(AgentConstants.CONFIG_CONNECTION_PASSWORD, PASSWORD);
+
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
+        configurationHandler.putAll(props);
+
         ConnectionHandler connectionHandler = m_agentContext.getHandler(ConnectionHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class))).andReturn("BASIC").anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_USERNAME), anyObject(String.class))).andReturn(m_user).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_PASSWORD), anyObject(String.class))).andReturn(m_pass).anyTimes();
-        replay(configurationHandler);
+
         HttpURLConnection connection = (HttpURLConnection) connectionHandler.getConnection(m_basicAuthURL);
         assertEquals(connection.getResponseCode(), HttpServletResponse.SC_OK);
     }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java Tue Sep 10 15:14:46 2013
@@ -18,11 +18,6 @@
  */
 package org.apache.ace.agent.impl;
 
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
 
@@ -33,6 +28,7 @@ import org.apache.ace.agent.AgentContext
 import org.apache.ace.agent.ConfigurationHandler;
 import org.apache.ace.agent.ConnectionHandler;
 import org.apache.ace.agent.DiscoveryHandler;
+import org.apache.ace.agent.EventsHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
 import org.apache.ace.agent.testutil.TestWebServer;
 import org.testng.annotations.AfterTest;
@@ -44,7 +40,8 @@ import org.testng.annotations.Test;
  */
 public class DiscoveryHandlerImplTest extends BaseAgentTest {
 
-    private final int PORT = 8882;
+    private static final int PORT = 8882;
+
     private TestWebServer m_webServer;
     private URL m_availableURL;
     private URL m_unavailableURL;
@@ -62,6 +59,8 @@ public class DiscoveryHandlerImplTest ex
         m_agentContextImpl = mockAgentContext();
         m_agentContext = m_agentContextImpl;
         m_agentContextImpl.setHandler(DiscoveryHandler.class, new DiscoveryHandlerImpl());
+        m_agentContextImpl.setHandler(EventsHandler.class, new EventsHandlerImpl(mockBundleContext()));
+        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
         m_agentContextImpl.setHandler(ConnectionHandler.class, new ConnectionHandlerImpl());
         replayTestMocks();
         m_agentContextImpl.start();
@@ -79,14 +78,10 @@ public class DiscoveryHandlerImplTest ex
     @Test
     public void testAvailableURL() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_availableURL.toExternalForm()).anyTimes();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_availableURL.toExternalForm());
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertEquals(discoveryHandler.getServerUrl(), m_availableURL);
     }
@@ -94,14 +89,10 @@ public class DiscoveryHandlerImplTest ex
     @Test
     public void testUnavailableURL_unavailable() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_unavailableURL.toExternalForm()).anyTimes();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_unavailableURL.toExternalForm());
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertNull(discoveryHandler.getServerUrl());
     }
@@ -109,50 +100,40 @@ public class DiscoveryHandlerImplTest ex
     @Test
     public void testUnavailableAfterConfigUpdate() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_availableURL.toExternalForm()).once();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_unavailableURL.toExternalForm()).once();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_availableURL.toExternalForm());
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertEquals(discoveryHandler.getServerUrl(), m_availableURL);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_unavailableURL.toExternalForm());
+
         assertNull(discoveryHandler.getServerUrl());
     }
 
     @Test
     public void testAvailableAfterConfigUpdate() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_unavailableURL.toExternalForm()).once();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_availableURL.toExternalForm()).once();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_unavailableURL.toExternalForm());
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertNull(discoveryHandler.getServerUrl());
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_availableURL.toExternalForm());
+
         assertEquals(discoveryHandler.getServerUrl(), m_availableURL);
     }
 
     @Test
     public void testAvailableAfterUnavailableURL() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn(m_unavailableURL.toExternalForm() + "," + m_availableURL.toExternalForm()).once();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, m_unavailableURL.toExternalForm() + "," + m_availableURL.toExternalForm());
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertEquals(discoveryHandler.getServerUrl(), m_availableURL);
     }
@@ -160,14 +141,10 @@ public class DiscoveryHandlerImplTest ex
     @Test
     public void testEmptyURLConfig() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn("").once();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, "");
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertNull(discoveryHandler.getServerUrl());
     }
@@ -175,14 +152,10 @@ public class DiscoveryHandlerImplTest ex
     @Test
     public void testBadURLConfig() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContext.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_CONNECTION_AUTHTYPE), anyObject(String.class)))
-            .andReturn(null).anyTimes();
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_DISCOVERY_SERVERURLS), anyObject(String.class)))
-            .andReturn("foobar").once();
-        expect(configurationHandler.getBoolean(AgentConstants.CONFIG_DISCOVERY_CHECKING, false))
-            .andReturn(true).anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, "invalidURL");
+        configurationHandler.put(AgentConstants.CONFIG_DISCOVERY_CHECKING, "true");
+
         DiscoveryHandler discoveryHandler = m_agentContext.getHandler(DiscoveryHandler.class);
         assertNull(discoveryHandler.getServerUrl());
     }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java Tue Sep 10 15:14:46 2013
@@ -18,11 +18,8 @@
  */
 package org.apache.ace.agent.impl;
 
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
@@ -32,6 +29,7 @@ import java.util.Set;
 
 import org.apache.ace.agent.AgentConstants;
 import org.apache.ace.agent.ConfigurationHandler;
+import org.apache.ace.agent.EventsHandler;
 import org.apache.ace.agent.FeedbackHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
 import org.testng.annotations.AfterMethod;
@@ -49,7 +47,11 @@ public class FeedbackHandlerImplTest ext
     public void setUpAgain(Method method) throws Exception {
         m_agentContextImpl = mockAgentContext(method.getName());
         replayTestMocks();
+
         m_agentContextImpl.setHandler(FeedbackHandler.class, new FeedbackHandlerImpl());
+        m_agentContextImpl.setHandler(EventsHandler.class, new EventsHandlerImpl(mockBundleContext()));
+        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
+
         m_agentContextImpl.start();
     }
 
@@ -61,33 +63,79 @@ public class FeedbackHandlerImplTest ext
     }
 
     @Test
-    public void testFeedbackChannelConfig() throws Exception {
+    public void testSingleFeedbackChannelConfig() throws Exception {
         ConfigurationHandler configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_FEEDBACK_CHANNELS),
-            anyObject(String.class))).andReturn("auditlog").anyTimes();
-        replay(configurationHandler);
+
+        configurationHandler.put(AgentConstants.CONFIG_FEEDBACK_CHANNELS, "auditlog");
 
         FeedbackHandler feedbackHandler = m_agentContextImpl.getHandler(FeedbackHandler.class);
+
         Set<String> names = feedbackHandler.getChannelNames();
         assertNotNull(names);
-        assertTrue(names.size() == 1);
+        assertEquals(1, names.size());
         assertTrue(names.contains("auditlog"));
+
         assertNotNull(feedbackHandler.getChannel("auditlog"));
-        assertNull(feedbackHandler.getChannel("QQQ"));
+        assertNull(feedbackHandler.getChannel("nonExistingChannel"));
+    }
 
-        reset(configurationHandler);
-        expect(configurationHandler.get(eq(AgentConstants.CONFIG_FEEDBACK_CHANNELS),
-            anyObject(String.class))).andReturn("auditlog, customchannel").anyTimes();
-        replay(configurationHandler);
+    @Test
+    public void testUpdateConfigAddFeedbackChannel() throws Exception {
+        ConfigurationHandler configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
+
+        configurationHandler.put(AgentConstants.CONFIG_FEEDBACK_CHANNELS, "auditlog");
+
+        FeedbackHandler feedbackHandler = m_agentContextImpl.getHandler(FeedbackHandler.class);
+
+        Set<String> names = feedbackHandler.getChannelNames();
+        assertNotNull(names);
+        assertEquals(1, names.size());
+        assertTrue(names.contains("auditlog"));
+
+        assertNotNull(feedbackHandler.getChannel("auditlog"));
+        assertNull(feedbackHandler.getChannel("nonExistingChannel"));
+
+        configurationHandler.put(AgentConstants.CONFIG_FEEDBACK_CHANNELS, "auditlog, customchannel");
 
         names = feedbackHandler.getChannelNames();
         assertNotNull(names);
-        assertTrue(names.size() == 2);
+        assertEquals(2, names.size());
         assertTrue(names.contains("auditlog"));
         assertTrue(names.contains("customchannel"));
+
         assertNotNull(feedbackHandler.getChannel("auditlog"));
         assertNotNull(feedbackHandler.getChannel("customchannel"));
-        assertNull(feedbackHandler.getChannel("QQQ"));
+        assertNull(feedbackHandler.getChannel("nonExistingChannel"));
+    }
+
+    @Test
+    public void testUpdateConfigRemoveFeedbackChannel() throws Exception {
+        ConfigurationHandler configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
+
+        configurationHandler.put(AgentConstants.CONFIG_FEEDBACK_CHANNELS, "auditlog, customchannel");
+
+        FeedbackHandler feedbackHandler = m_agentContextImpl.getHandler(FeedbackHandler.class);
+
+        Set<String> names = feedbackHandler.getChannelNames();
+        assertNotNull(names);
+        assertEquals(2, names.size());
+        assertTrue(names.contains("auditlog"));
+        assertTrue(names.contains("customchannel"));
+
+        assertNotNull(feedbackHandler.getChannel("auditlog"));
+        assertNotNull(feedbackHandler.getChannel("customchannel"));
+        assertNull(feedbackHandler.getChannel("nonExistingChannel"));
+
+        configurationHandler.put(AgentConstants.CONFIG_FEEDBACK_CHANNELS, "auditlog");
+
+        names = feedbackHandler.getChannelNames();
+        assertNotNull(names);
+        assertEquals(1, names.size());
+        assertTrue(names.contains("auditlog"));
+        assertFalse(names.contains("customchannel"));
+
+        assertNotNull(feedbackHandler.getChannel("auditlog"));
+        assertNull(feedbackHandler.getChannel("customchannel"));
+        assertNull(feedbackHandler.getChannel("nonExistingChannel"));
     }
 }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java Tue Sep 10 15:14:46 2013
@@ -18,63 +18,95 @@
  */
 package org.apache.ace.agent.testutil;
 
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
+import static org.easymock.EasyMock.*;
 
 import java.io.File;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Stack;
+import java.util.concurrent.ScheduledExecutorService;
 
 import org.apache.ace.agent.AgentContext;
 import org.apache.ace.agent.AgentContextAware;
 import org.apache.ace.agent.impl.AgentContextImpl;
+import org.osgi.framework.BundleContext;
 
 /**
  * Simple base class.
  */
 public abstract class BaseAgentTest {
+    private final Set<Object> m_mocks = new HashSet<Object>();
 
-    private Set<Object> m_mocks = new HashSet<Object>();
+    protected <T> T addTestMock(Class<T> clazz) {
+        T mock = createNiceMock(clazz);
+        m_mocks.add(mock);
+        return mock;
+    }
+
+    protected void cleanDir(File dir) {
+        if (!dir.isDirectory())
+            throw new IllegalStateException();
+        Stack<File> dirs = new Stack<File>();
+        dirs.push(dir);
+        while (!dirs.isEmpty()) {
+            File currentDir = dirs.pop();
+            File[] files = currentDir.listFiles();
+            for (File file : files) {
+                if (file.isDirectory()) {
+                    dirs.push(file);
+                }
+                else {
+                    file.delete();
+                }
+            }
+        }
+    }
+
+    protected void clearTestMocks() {
+        m_mocks.clear();
+    }
+
+    protected File getWorkDir() {
+        return new File("generated");
+    }
 
     protected AgentContextImpl mockAgentContext() throws Exception {
-        return mockAgentContext("" + System.currentTimeMillis());
+        return mockAgentContext("mockAgentContext" + System.currentTimeMillis());
     }
 
     protected AgentContextImpl mockAgentContext(String subDir) throws Exception {
         File contextDir = new File(getWorkDir(), subDir);
         contextDir.mkdirs();
         cleanDir(contextDir);
+
         AgentContextImpl context = new AgentContextImpl(contextDir);
         for (Class<?> handlerClass : AgentContextImpl.KNOWN_HANDLERS) {
-            context.setHandler(handlerClass, addTestMock(handlerClass));
+            if (ScheduledExecutorService.class.equals(handlerClass)) {
+                // always inject a proper executor service that simply invokes synchronously...
+                context.setHandler(ScheduledExecutorService.class, new SynchronousExecutorService());
+            }
+            else {
+                setMockedHandler(context, handlerClass);
+            }
         }
         return context;
     }
 
-    protected <T extends Object> T addTestMock(Class<T> clazz) {
-        T mock = createNiceMock(clazz);
-        m_mocks.add(mock);
-        return mock;
+    protected BundleContext mockBundleContext() throws Exception {
+        BundleContext result = createNiceMock(BundleContext.class);
+        expect(result.createFilter(anyObject(String.class))).andReturn(null).anyTimes();
+        replay(result);
+        return result;
     }
 
     protected void replayTestMocks() {
-        for (Object mock : m_mocks)
+        for (Object mock : m_mocks) {
             replay(mock);
+        }
     }
 
-    protected void verifyTestMocks() {
-        for (Object mock : m_mocks)
-            verify(mock);
-    }
-
-    protected void clearTestMocks() {
-        m_mocks.clear();
-    }
-
-    protected File getWorkDir() {
-        return new File("generated");
+    protected <T> void setMockedHandler(AgentContextImpl context, Class<T> clazz) {
+        context.setHandler(clazz, addTestMock(clazz));
     }
 
     protected void startHandler(Object handler, AgentContext agentContext) throws Exception {
@@ -89,22 +121,9 @@ public abstract class BaseAgentTest {
         }
     }
 
-    protected void cleanDir(File dir) {
-        if (!dir.isDirectory())
-            throw new IllegalStateException();
-        Stack<File> dirs = new Stack<File>();
-        dirs.push(dir);
-        while (!dirs.isEmpty()) {
-            File currentDir = dirs.pop();
-            File[] files = currentDir.listFiles();
-            for (File file : files) {
-                if (file.isDirectory()) {
-                    dirs.push(file);
-                }
-                else {
-                    file.delete();
-                }
-            }
+    protected void verifyTestMocks() {
+        for (Object mock : m_mocks) {
+            verify(mock);
         }
     }
 }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/TestWebServer.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/TestWebServer.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/TestWebServer.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/TestWebServer.java Tue Sep 10 15:14:46 2013
@@ -42,85 +42,51 @@ import org.eclipse.jetty.servlet.Servlet
 import org.eclipse.jetty.servlet.ServletHolder;
 
 /**
- * Test utility that manages a Jetty webserver with a {@link DefaultServlet} that support HTTP range downloads and a simple
- * HTTP protocol dump filter. It can be extended with custom test servlets.
+ * Test utility that manages a Jetty webserver with a {@link DefaultServlet} that support HTTP range downloads and a
+ * simple HTTP protocol dump filter. It can be extended with custom test servlets.
  */
 public class TestWebServer {
 
-    private Server m_server;
-    private ServletContextHandler m_contextHandler;
-
-    public TestWebServer(int port, String contextPath, String basePath) throws Exception {
-
-        m_server = new Server(port);
-
-        m_contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
-        m_contextHandler.setContextPath("/");
-
-        ServletHolder holder = new ServletHolder(new DefaultServlet());
-        holder.setInitParameter("resourceBase", basePath);
-        holder.setInitParameter("pathInfoOnly", "true");
-        holder.setInitParameter("acceptRanges", "true");
-        holder.setInitParameter("dirAllowed", "true");
-
-        m_contextHandler.addFilter(new FilterHolder(new HttpDumpFilter()), "/*", null);
-        m_contextHandler.addServlet(holder, contextPath.concat(contextPath.endsWith("/") ? "*" : "/*"));
-        m_server.setHandler(m_contextHandler);
-    }
-
-    public void start() throws Exception {
-        m_server.start();
-    }
-
-    public void stop() throws Exception {
-        m_server.stop();
-        m_server.join();
-    }
-
-    public void addServlet(Servlet servlet, String pathPsec) {
-        m_contextHandler.addServlet(new ServletHolder(servlet), pathPsec);
-    }
-
     static class HttpDumpFilter implements Filter {
-
-        @Override
-        public void init(FilterConfig arg0) throws ServletException {
-        }
-
         @Override
         public void destroy() {
+            // Nop
         }
 
         @Override
+        @SuppressWarnings("unchecked")
         public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
             HttpServletRequest hreq = (HttpServletRequest) req;
             HttpServletResponse hres = (HttpServletResponse) res;
 
-            @SuppressWarnings("unchecked")
+            ResponseInfoCollector coll = new ResponseInfoCollector(hres);
+            chain.doFilter(req, coll);
+
+            StringBuilder sb = new StringBuilder();
+            sb.append("> ").append(hreq.getMethod()).append(" ").append(hreq.getRequestURI()).append(" ").append(req.getProtocol()).append('\n');
             Enumeration<String> attrs = hreq.getHeaderNames();
-            System.out.println("> " + hreq.getMethod() + " " + hreq.getRequestURI() + " " + req.getProtocol());
             while (attrs.hasMoreElements()) {
                 String attr = attrs.nextElement();
-                System.out.println("> " + attr + ":" + hreq.getHeader(attr));
+                sb.append("> ").append(attr).append(": ").append(hreq.getHeader(attr)).append('\n');
             }
-            ResponseInfoCollector coll = new ResponseInfoCollector(hres);
-            chain.doFilter(req, coll);
 
-            // servlet API 3.0
-            // System.out.println("< " + res.getStatus());
-            // for (String headerName : res.getHeaderNames())
-            // System.out.println("< " + headerName + ":" + res.getHeader(headerName));
-            System.out.println("< " + coll.statusCode + " " + coll.statusMessage);
+            sb.append("< ").append(hreq.getProtocol()).append(" ").append(coll.statusCode).append(" ").append(coll.statusMessage).append('\n');
             for (String headerName : coll.headers.keySet()) {
-                System.out.println("< " + headerName + ":" + coll.headers.get(headerName));
+                sb.append("< ").append(headerName).append(": ").append(coll.headers.get(headerName)).append('\n');
             }
+
+            System.out.println(sb);
+        }
+
+        @Override
+        public void init(FilterConfig config) throws ServletException {
+            // Nop
         }
     }
 
     static class ResponseInfoCollector extends HttpServletResponseWrapper {
-
         long statusCode;
-        String statusMessage;
+        String statusMessage = "";
         Map<String, String> headers = new HashMap<String, String>();
 
         public ResponseInfoCollector(HttpServletResponse response) {
@@ -128,9 +94,16 @@ public class TestWebServer {
         }
 
         @Override
-        public void setHeader(String name, String value) {
-            headers.put(name, value);
-            super.setHeader(name, value);
+        public void sendError(int sc) throws IOException {
+            statusCode = sc;
+            super.sendError(sc);
+        }
+
+        @Override
+        public void sendError(int sc, String msg) throws IOException {
+            statusCode = sc;
+            statusMessage = msg;
+            super.sendError(sc, msg);
         }
 
         @Override
@@ -140,22 +113,61 @@ public class TestWebServer {
         }
 
         @Override
+        public void setHeader(String name, String value) {
+            headers.put(name, value);
+            super.setHeader(name, value);
+        }
+
+        @Override
         public void setIntHeader(String name, int value) {
             headers.put(name, "" + value);
             super.setIntHeader(name, value);
         }
 
         @Override
-        public void setStatus(int sc, String sm) {
+        public void setStatus(int sc) {
             statusCode = sc;
-            statusMessage = sm;
-            super.setStatus(sc, sm);
+            super.setStatus(sc);
         }
 
         @Override
-        public void setStatus(int sc) {
+        public void setStatus(int sc, String sm) {
             statusCode = sc;
-            super.setStatus(sc);
+            statusMessage = sm;
+            super.setStatus(sc, sm);
         }
     }
+
+    private final ServletContextHandler m_contextHandler;
+    private final Server m_server;
+
+    public TestWebServer(int port, String contextPath, String basePath) throws Exception {
+        m_server = new Server(port);
+
+        m_contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
+        m_contextHandler.setContextPath("/");
+
+        ServletHolder holder = new ServletHolder(new DefaultServlet());
+        holder.setInitParameter("resourceBase", basePath);
+        holder.setInitParameter("pathInfoOnly", "true");
+        holder.setInitParameter("acceptRanges", "true");
+        holder.setInitParameter("dirAllowed", "true");
+
+        m_contextHandler.addFilter(new FilterHolder(new HttpDumpFilter()), "/*", null);
+        m_contextHandler.addServlet(holder, contextPath.concat(contextPath.endsWith("/") ? "*" : "/*"));
+        m_server.setHandler(m_contextHandler);
+    }
+
+    public void addServlet(Servlet servlet, String pathPsec) {
+        m_contextHandler.addServlet(new ServletHolder(servlet), pathPsec);
+    }
+
+    public void start() throws Exception {
+        m_server.start();
+    }
+
+    public void stop() throws Exception {
+        m_server.stop();
+        m_server.join();
+    }
 }