You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2011/03/04 14:48:18 UTC

svn commit: r1077946 - in /cxf/trunk/rt/management-web/src: main/java/org/apache/cxf/management/web/logging/ test/java/org/ test/java/org/apache/ test/java/org/apache/cxf/ test/java/org/apache/cxf/management/ test/java/org/apache/cxf/management/web/ te...

Author: sergeyb
Date: Fri Mar  4 13:48:18 2011
New Revision: 1077946

URL: http://svn.apache.org/viewvc?rev=1077946&view=rev
Log:
[CXF-3372] Adding a helper for reading arbitrary log files with an optional scanning

Added:
    cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java   (with props)
    cxf/trunk/rt/management-web/src/test/java/org/
    cxf/trunk/rt/management-web/src/test/java/org/apache/
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java   (with props)
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log
    cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log.1
Modified:
    cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadableLogStorage.java

Added: cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java?rev=1077946&view=auto
==============================================================================
--- cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java (added)
+++ cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java Fri Mar  4 13:48:18 2011
@@ -0,0 +1,477 @@
+/**
+ * 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.cxf.management.web.logging;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+
+/**
+ * Facilitates reading the log entries from the existing log files
+ */
+public class ReadOnlyFileStorage implements ReadableLogStorage {
+    
+    public static final String LEVEL_PROPERTY = "level";
+    public static final String DATE_PROPERTY = "date";
+    public static final String MESSAGE_PROPERTY = "message";
+    public static final String CATEGORY_PROPERTY = "category";
+    public static final String THREAD_PROPERTY = "thread";
+    
+    public static final String DATE_ONLY_FORMAT = "yyyy_MM_dd";
+        
+    private static final String LINE_SEP = System.getProperty("line.separator"); 
+    
+    private String columnSep;
+    private int numberOfColumns;
+    private boolean startsFromSeparator;
+    private boolean endsWithSeparator;
+    
+    private SimpleDateFormat recordDateFormat;
+    private boolean useFileModifiedDate;
+    private Pattern fileNameDatePattern;
+    private String fileNameDateFormat;
+    
+    private File logDirectory; 
+    private Comparator<String> fileNameComparator;
+    
+    private Map<Integer, String> columnsMap;
+    private List<FileInfo> logFiles 
+        = Collections.synchronizedList(new LinkedList<FileInfo>());  
+    private Map<String, String> levelsMap;
+    private ConcurrentHashMap<Integer, PageInfo> pagesMap
+        = new ConcurrentHashMap<Integer, PageInfo>();
+    
+    
+    @Override
+    public int getSize() {
+        return -1;
+    }
+
+    @Override
+    public void load(List<LogRecord> list, 
+                     SearchCondition<LogRecord> condition, 
+                     int pageNumber,
+                     int pageSize) {
+        FileInfo logFileInfo = getLogFileInfo(pageNumber, true);
+        if (logFileInfo == null) {
+            return;
+        }
+        
+        int count = 0;
+        while (true) {
+            LogRecord record = readRecord(logFileInfo);
+            if (record == null) {
+                logFileInfo = getNextLogFileInfo(logFileInfo, true);
+                if (logFileInfo != null) {
+                    continue;
+                } else {
+                    return;
+                }
+            }
+            if (condition == null || condition.isMet(record)) {
+                list.add(record);
+                if (++count == pageSize) {
+                    break;
+                }
+            }
+        }
+        savePagePosition(pageNumber, logFileInfo);
+
+    }
+
+    private FileInfo getNextLogFileInfo(FileInfo logFileInfo, boolean firstTry) {
+        for (Iterator<FileInfo> it = logFiles.iterator(); it.hasNext();) {
+            FileInfo fileInfo = it.next();
+            if (fileInfo == logFileInfo && it.hasNext()) {
+                return it.next(); 
+            } else {
+                break;
+            }
+        }
+        if (firstTry && logDirectory != null && scanLogDirectory()) {
+            return getNextLogFileInfo(logFileInfo, false);
+        }
+        return null;
+    }
+    
+    private FileInfo getLogFileInfo(int pageNumber, boolean firstTry) {
+        PageInfo pageInfo = pagesMap.get(pageNumber);
+        if (pageInfo != null) {
+            FileInfo fileInfo = pageInfo.getFileInfo();
+            try {
+                fileInfo.getFile().seek(pageInfo.getPosition());
+            } catch (IOException ex) {
+                System.err.println("Problem setting a page position in " + fileInfo.getFileName());
+                return null;
+            }
+            return pageInfo.getFileInfo();
+        }
+        if (pageNumber == 1 
+            && logDirectory != null 
+            && firstTry 
+            && logFiles.size() == 0
+            && scanLogDirectory()) {
+            FileInfo fileInfo = logFiles.get(0);
+            savePagePosition(0, fileInfo);
+            return fileInfo;
+        }
+        return null;
+    }
+    
+    
+    private void savePagePosition(int pageNumber, FileInfo fileInfo) {
+        try {
+            long pos = fileInfo.getFile().getFilePointer();
+            pagesMap.put(pageNumber + 1, new PageInfo(fileInfo, pos));
+        } catch (IOException ex) {
+            // ignore
+        }
+        
+    }
+    
+    protected LogRecord readRecord(FileInfo logFileInfo) {
+        try {
+            Map<Integer, String> map = new HashMap<Integer, String>(numberOfColumns);
+            readTheLine(logFileInfo.getFile(), map, 1);
+            return createRecord(map, logFileInfo);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+        
+    }
+    
+    protected LogRecord createRecord(Map<Integer, String> map, FileInfo logFileInfo) {
+        if (map.isEmpty()) {
+            return null;
+        }
+        LogRecord record = new LogRecord();
+        for (Map.Entry<Integer, String> entry : map.entrySet()) {
+            String propertyName = columnsMap.get(entry.getKey());
+            if (LEVEL_PROPERTY.equals(propertyName)) {
+                setLogRecordLevel(record, entry.getValue());
+            } else if (DATE_PROPERTY.equals(propertyName)) {
+                setLogRecordDate(record, entry.getValue(), logFileInfo);
+            } else if (MESSAGE_PROPERTY.equals(propertyName)) {
+                record.setMessage(entry.getValue());
+            } else if (CATEGORY_PROPERTY.equals(propertyName)) {
+                record.setLoggerName(entry.getValue());
+            } else if (THREAD_PROPERTY.equals(propertyName)) {
+                record.setThreadName(entry.getValue());
+            }
+        }
+        return record;
+    }
+    
+    protected void setLogRecordLevel(LogRecord record, String logLevel) {
+        if (levelsMap != null) {
+            logLevel = levelsMap.get(logLevel);
+        }
+        if (logLevel != null) {
+            record.setLevel(LogLevel.valueOf(logLevel));
+        }
+    }
+    
+    protected void setLogRecordDate(LogRecord record, String logDate, FileInfo logFileInfo) {
+        if (recordDateFormat != null) {
+            try {
+                String fileModifiedDate = logFileInfo.getFileModified();
+                logDate = fileModifiedDate != null ? fileModifiedDate + " " + logDate : logDate;
+                Date date = recordDateFormat.parse(logDate);
+                record.setEventTimestamp(date);
+            } catch (Exception ex) {
+                // ignore
+            }
+        }
+    }
+    
+    protected void readTheLine(RandomAccessFile logFile, Map<Integer, String> map, int columnIndex) 
+        throws IOException {
+        
+        long nextPos = logFile.getFilePointer();
+        if (nextPos >= logFile.length()) {
+            return;
+        }
+        
+        String line = logFile.readLine();
+        
+        int lastIndex = 0;
+        if (columnIndex == 1 && startsFromSeparator) {
+            lastIndex = 1;
+        }
+            
+        Set<Integer> requestedColumns = columnsMap.keySet();
+        int startingColumn = columnIndex;
+        while (lastIndex < line.length()) {
+        
+            int sepIndex = line.indexOf(columnSep, lastIndex);
+            
+            if (sepIndex != -1 && startingColumn == numberOfColumns && !endsWithSeparator) {
+                logFile.seek(nextPos);
+                return;
+            }
+            
+            int actualIndex = sepIndex  == -1 ? line.length() : sepIndex;
+            
+            if (requestedColumns.contains(columnIndex)) {
+                String value = line.substring(lastIndex, actualIndex).trim();
+                String existingValue = map.get(columnIndex);
+                map.put(columnIndex, existingValue == null 
+                                     ? value : existingValue + LINE_SEP + value);
+            }
+            
+            lastIndex = actualIndex + 1;
+            if (sepIndex != -1 && columnIndex != numberOfColumns) {
+                columnIndex++;
+            }
+        }
+        
+        if (columnIndex == numberOfColumns) {
+            readTheLine(logFile, map, columnIndex);
+        }
+    }
+    
+    public void setColumnSep(String columnSep) {
+        this.columnSep = columnSep;
+    }
+
+    public void setNumberOfColums(String number) {
+        this.numberOfColumns = Integer.parseInt(number);
+    }
+
+    public void setColumnsMap(Map<Integer, String> columnsMap) {
+        this.columnsMap = columnsMap;
+    }
+
+    public void setLogLocations(List<String> locations) {
+        logFiles = new LinkedList<FileInfo>();
+        for (int i = 0; i < locations.size(); i++) {
+            String realPath = getRealLocation(locations.get(i));
+            
+            try {
+                processNewLogFile(new File(realPath));
+            } catch (IOException ex) {
+                throw new RuntimeException("The log file " + realPath + " can not be opened: "
+                                           + ex.getMessage());
+            }
+        }
+    }
+    
+    private void processNewLogFile(File file) throws IOException {
+        RandomAccessFile logFile = new RandomAccessFile(file, "r");
+        
+        String fileModifiedDate = null;
+        if (useFileModifiedDate) {
+            String dateFormat = fileNameDateFormat == null ? DATE_ONLY_FORMAT : fileNameDateFormat;
+            
+            if (fileNameDatePattern != null) {
+                Matcher m = fileNameDatePattern.matcher(file.getName());
+                if (m.find()) {
+                    fileModifiedDate = m.group();
+                }
+            }
+            if (fileModifiedDate == null) {
+                Date fileDate = new Date(file.lastModified());
+                fileModifiedDate = new SimpleDateFormat(dateFormat).format(fileDate);
+            }
+        }
+        
+        FileInfo fileInfo = new FileInfo(logFile, file.getName(), fileModifiedDate);
+        skipIgnorableRecords(fileInfo, logFiles.size() == 0);
+        logFiles.add(fileInfo);
+    }
+    
+    private String getRealLocation(String location) {
+        int indexOpen = location.indexOf("{");
+        int indexClose = location.indexOf("}");
+        String realPath = null;
+        if (indexOpen == 0 && indexClose != -1) {
+            realPath = location.substring(1, indexClose)
+                       + location.substring(indexClose + 1);
+            
+        } else {
+            realPath = location;
+        }
+        return realPath;
+    }
+    
+    public void setLogLocation(String location) {
+        String realPath = getRealLocation(location);
+        File file = new File(realPath);
+        if (file.isDirectory()) {
+            logDirectory = file;
+        } else {
+            setLogLocations(Collections.singletonList(realPath));
+        }
+    }
+    
+    private void skipIgnorableRecords(FileInfo fInfo, boolean first) throws IOException {
+        long nextPos = fInfo.getFile().getFilePointer();
+        String line = fInfo.getFile().readLine();
+        if (line.contains(columnSep)) {
+            fInfo.getFile().seek(nextPos);
+            if (first) {
+                pagesMap.put(1, new PageInfo(fInfo, nextPos));
+            }
+        } else {
+            skipIgnorableRecords(fInfo, first);
+        }
+        
+    }
+    
+    public void setRecordDateFormat(String format) {
+        recordDateFormat = new SimpleDateFormat(format);
+    }
+    
+    public void setLevelsMap(Map<String, String> map) {
+        this.levelsMap = map;
+    }
+    
+    public void setFileNameComparator(Comparator<String> comp) {
+        this.fileNameComparator = comp;
+    }
+    
+    public void close() {
+        for (FileInfo fileInfo : logFiles) {
+            try {
+                fileInfo.getFile().close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    public void setUseFileModifiedDate(boolean useFileModifiedDate) {
+        this.useFileModifiedDate = useFileModifiedDate;
+    }
+
+    private boolean scanLogDirectory() {
+        int oldSize = logFiles.size();
+        for (File file : logDirectory.listFiles()) {
+            // just in case
+            if (file.isDirectory()) {
+                // continue
+            }
+            boolean isNew = true;
+            for (FileInfo fInfo : logFiles) {
+                if (fInfo.getFileName().equalsIgnoreCase(file.getName())) {
+                    isNew = false;
+                    break;
+                }
+            }
+            if (isNew) {
+                try {
+                    processNewLogFile(file);
+                } catch (IOException ex) {
+                    System.out.println("Log file " + file.getName() + " can not be opened");
+                }
+            }
+        }
+        if (logFiles.size() > oldSize) {
+            Collections.sort(logFiles, new FileInfoComparator());
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    public void setFileNameDatePattern(String fileNameDatePattern) {
+        this.fileNameDatePattern = Pattern.compile(fileNameDatePattern);
+    }
+
+    public void setFileNameDateFormat(String fileNameDateFormat) {
+        this.fileNameDateFormat = fileNameDateFormat;
+    }
+
+    protected static class PageInfo {
+        private FileInfo fileInfo;
+        private long pos;
+        public PageInfo(FileInfo fileInfo, long pos) {
+            this.fileInfo = fileInfo;
+            this.pos = pos;
+        }
+        
+        public FileInfo getFileInfo() {
+            return fileInfo;
+        }
+        public long getPosition() {
+            return pos;
+        }
+    }
+    
+    protected static class FileInfo {
+        private RandomAccessFile file;
+        private String fileModified;
+        private String fileName;
+        
+        public FileInfo(RandomAccessFile file, String fileName, String fileModified) {
+            this.file = file;
+            this.fileModified = fileModified;
+            this.fileName = fileName;
+        }
+        
+        public RandomAccessFile getFile() {
+            return file;
+        }
+        public String getFileModified() {
+            return fileModified;
+        }
+        public String getFileName() {
+            return fileName;
+        }
+    }
+ 
+    protected class FileInfoComparator implements Comparator<FileInfo> {
+
+        @Override
+        public int compare(FileInfo info1, FileInfo info2) {
+            String name1 = info1.getFileName();
+            String name2 = info2.getFileName();
+            if (fileNameComparator != null) {
+                return fileNameComparator.compare(name1, name2);
+            }
+            Integer logIndex1 = getLogIndex(name1);
+            Integer logIndex2 = getLogIndex(name2);
+            return logIndex1.compareTo(logIndex2) * -1;
+        } 
+        
+        private int getLogIndex(String name) {
+            int index = name.lastIndexOf('.');
+            try {
+                return Integer.valueOf(name.substring(index + 1));
+            } catch (Exception ex) {
+                return 0;
+            }    
+        }
+    }
+}

Propchange: cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorage.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadableLogStorage.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadableLogStorage.java?rev=1077946&r1=1077945&r2=1077946&view=diff
==============================================================================
--- cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadableLogStorage.java (original)
+++ cxf/trunk/rt/management-web/src/main/java/org/apache/cxf/management/web/logging/ReadableLogStorage.java Fri Mar  4 13:48:18 2011
@@ -33,13 +33,13 @@ public interface ReadableLogStorage {
      * Read the records and load them into a provided list
      * @param list the list saved records should be added to
      * @param condition the condition loaded records must meet, can be null 
-     * @param loadFrom the initial index of the storage to have records loaded from
-     * @param int maxNumberOfRecords the max number of records to load from the storage
+     * @param pageNumber the initial page to have records loaded from
+     * @param int pageSize the max number of records to load from the storage
      */
     void load(List<LogRecord> list, 
               SearchCondition<LogRecord> condition,
-              int loadFrom, 
-              int maxNumberOfRecords);
+              int pageNumber, 
+              int pageSize);
     
     
     /**

Added: cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java?rev=1077946&view=auto
==============================================================================
--- cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java (added)
+++ cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java Fri Mar  4 13:48:18 2011
@@ -0,0 +1,175 @@
+/**
+ * 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.cxf.management.web.logging;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReadOnlyFileStorageTest extends Assert {
+    
+    private ReadOnlyFileStorage storage;
+    
+    @Before
+    public void setUp() throws Exception {
+        storage = new ReadOnlyFileStorage();
+       
+        storage.setNumberOfColums("7");
+        storage.setColumnSep("|");
+              
+        Map<Integer, String> columnsMap = new HashMap<Integer, String>(); 
+        columnsMap.put(1, ReadOnlyFileStorage.DATE_PROPERTY);
+        columnsMap.put(2, ReadOnlyFileStorage.LEVEL_PROPERTY);
+        columnsMap.put(7, ReadOnlyFileStorage.MESSAGE_PROPERTY);
+       
+        storage.setColumnsMap(columnsMap);
+       
+        storage.setRecordDateFormat(ReadOnlyFileStorage.DATE_ONLY_FORMAT 
+                                   + " " + "kk:mm:ss,SSS");
+        storage.setUseFileModifiedDate(true);
+       
+       
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+        storage.close();
+    }
+    
+    @Test
+    public void testReadRecords() throws Exception {
+        
+        storage.setLogLocation(getClass().getResource("logs/karaf.log.1").toURI().getPath());
+        List<LogRecord> recordsFirstPage1 = readPage(1, 10, 10);
+        
+        readPage(2, 10, 10);
+        readPage(3, 10, 10);
+        List<LogRecord> recordsLastPage1 = readPage(4, 10, 2);
+        
+        List<LogRecord> recordsFirstPage2 = readPage(1, 10, 10);
+        compareRecords(recordsFirstPage1, recordsFirstPage2);
+        
+        List<LogRecord> recordsLastPage2 = readPage(4, 10, 2);
+        compareRecords(recordsLastPage1, recordsLastPage2);
+        
+        LogRecord lastRecord = recordsLastPage1.get(1);
+        assertTrue(lastRecord.getMessage().contains("Pax Web available at"));
+    }
+    
+    @Test
+    public void testReadRecordsWithMultiLines() throws Exception {
+        
+        storage.setLogLocation(getClass().getResource("logs/karaf.log").toURI().getPath());
+        List<LogRecord> recordsFirstPage1 = readPage(1, 10, 10);
+        
+        List<LogRecord> recordsLastPage1 = readPage(2, 10, 10);
+        
+        List<LogRecord> recordsFirstPage2 = readPage(1, 10, 10);
+        compareRecords(recordsFirstPage1, recordsFirstPage2);
+        
+        List<LogRecord> recordsLastPage2 = readPage(2, 10, 10);
+        compareRecords(recordsLastPage1, recordsLastPage2);
+        
+        LogRecord recordWithExceptionInMessage = recordsFirstPage1.get(2);
+        assertEquals(LogLevel.ERROR, recordWithExceptionInMessage.getLevel());
+        assertTrue(recordWithExceptionInMessage.getMessage()
+                   .contains("mvn:org.apache.cxf/cxf-bundle/"));
+        assertTrue(recordWithExceptionInMessage.getMessage()
+                   .contains("Caused by: org.osgi.framework.BundleException"));
+    }
+    
+    @Test
+    public void testReadRecordsWithMultipleFiles() throws Exception {
+        
+        List<String> locations = new ArrayList<String>();
+        locations.add(getClass().getResource("logs/karaf.log.1").toURI().getPath());
+        locations.add(getClass().getResource("logs/karaf.log").toURI().getPath());
+        storage.setLogLocations(locations);
+        List<LogRecord> recordsFirstPage1 = readPage(1, 10, 10);
+        readPage(2, 10, 10);
+        readPage(3, 10, 10);
+        List<LogRecord> recordsPage4 = readPage(4, 10, 10);
+        readPage(5, 10, 10);
+        List<LogRecord> recordsLastPage1 = readPage(6, 10, 2);
+        
+        LogRecord recordWithExceptionInMessage = recordsPage4.get(4);
+        assertEquals(LogLevel.ERROR, recordWithExceptionInMessage.getLevel());
+        assertTrue(recordWithExceptionInMessage.getMessage()
+                   .contains("mvn:org.apache.cxf/cxf-bundle/"));
+        assertTrue(recordWithExceptionInMessage.getMessage()
+                   .contains("Caused by: org.osgi.framework.BundleException"));
+        
+        List<LogRecord> recordsFirstPage2 = readPage(1, 10, 10);
+        compareRecords(recordsFirstPage1, recordsFirstPage2);
+        
+        List<LogRecord> recordsLastPage2 = readPage(6, 10, 2);
+        compareRecords(recordsLastPage1, recordsLastPage2);
+    }
+    
+    @Test
+    public void testReadRecordsWithScanDirectory() throws Exception {
+        
+        String dir = getClass().getResource("logs").toURI().getPath();
+        storage.setLogLocation(dir);
+        List<LogRecord> recordsFirstPage1 = readPage(1, 10, 10);
+        readPage(2, 10, 10);
+        readPage(3, 10, 10);
+        List<LogRecord> recordsPage4 = readPage(4, 10, 10);
+        readPage(5, 10, 10);
+        List<LogRecord> recordsLastPage1 = readPage(6, 10, 2);
+        
+        LogRecord recordWithExceptionInMessage = recordsPage4.get(4);
+        assertEquals(LogLevel.ERROR, recordWithExceptionInMessage.getLevel());
+        assertTrue(recordWithExceptionInMessage.getMessage()
+                   .contains("mvn:org.apache.cxf/cxf-bundle/"));
+        assertTrue(recordWithExceptionInMessage.getMessage()
+                   .contains("Caused by: org.osgi.framework.BundleException"));
+        
+        List<LogRecord> recordsFirstPage2 = readPage(1, 10, 10);
+        compareRecords(recordsFirstPage1, recordsFirstPage2);
+        
+        List<LogRecord> recordsLastPage2 = readPage(6, 10, 2);
+        compareRecords(recordsLastPage1, recordsLastPage2);
+    }
+    
+    private void compareRecords(List<LogRecord> records1, List<LogRecord> records2) {
+        for (int i = 0; i < records1.size(); i++) {
+            LogRecord r1 = records1.get(i);
+            LogRecord r2 = records2.get(i);
+            assertEquals(r1.getLevel(), r2.getLevel());
+            assertEquals(r1.getEventTimestamp(), r2.getEventTimestamp());
+            assertEquals(r1.getMessage(), r2.getMessage());
+        }    
+    }
+    
+    private List<LogRecord> readPage(int page, int pageSize, int expected) {
+        List<LogRecord> records = new ArrayList<LogRecord>();
+        storage.load(records, null, page, pageSize);
+        assertEquals(expected, records.size());
+        return records;
+        
+    }
+
+}

Propchange: cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/ReadOnlyFileStorageTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log?rev=1077946&view=auto
==============================================================================
--- cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log (added)
+++ cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log Fri Mar  4 13:48:18 2011
@@ -0,0 +1,31 @@
+11:49:17,821 | INFO  | Thread-11        | HttpServiceFactoryImpl           | .internal.HttpServiceFactoryImpl   33 | 67 - org.ops4j.pax.web.pax-web-runtime - 0.7.4 | Binding bundle: [org.apache.karaf.deployer.features_2.1.4 [27]] to http service
+11:49:17,865 | INFO  | guration Updater | JettyServerImpl                  | e.jetty.internal.JettyServerImpl  100 | 68 - org.ops4j.pax.web.pax-web-jetty - 0.7.4 | Pax Web available at [0.0.0.0]:[8080]
+11:49:18,356 | ERROR | Thread-4         | FeaturesServiceImpl              | s.internal.FeaturesServiceImpl$1  814 | 26 - org.apache.karaf.features.core - 2.1.4 | Error installing boot features
+java.lang.Exception: Could not start bundle mvn:org.apache.cxf/cxf-bundle/2.4.0-SNAPSHOT in feature(s) cxf-2.4.0-SNAPSHOT: The bundle "org.apache.cxf.bundle_2.4.0.SNAPSHOT [110]" could not be resolved. Reason: Missing Constraint: Import-Package: org.apache.neethi; version="[3.0.0,4.0.0)"
+	at org.apache.karaf.features.internal.FeaturesServiceImpl.installFeatures(FeaturesServiceImpl.java:326)[26:org.apache.karaf.features.core:2.1.4]
+	at org.apache.karaf.features.internal.FeaturesServiceImpl$1.run(FeaturesServiceImpl.java:812)[26:org.apache.karaf.features.core:2.1.4]
+Caused by: org.osgi.framework.BundleException: The bundle "org.apache.cxf.bundle_2.4.0.SNAPSHOT [110]" could not be resolved. Reason: Missing Constraint: Import-Package: org.apache.neethi; version="[3.0.0,4.0.0)"
+	at org.eclipse.osgi.framework.internal.core.AbstractBundle.getResolverError(AbstractBundle.java:1317)[osgi-3.6.0.v20100517.jar:]
+	at org.eclipse.osgi.framework.internal.core.AbstractBundle.getResolutionFailureException(AbstractBundle.java:1301)[osgi-3.6.0.v20100517.jar:]
+	at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:319)[osgi-3.6.0.v20100517.jar:]
+	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:284)[osgi-3.6.0.v20100517.jar:]
+	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:276)[osgi-3.6.0.v20100517.jar:]
+	at org.apache.karaf.features.internal.FeaturesServiceImpl.installFeatures(FeaturesServiceImpl.java:323)[26:org.apache.karaf.features.core:2.1.4]
+	... 1 more
+11:49:24,415 | INFO  |  Bundle Shutdown | ContextLoaderListener            | .activator.ContextLoaderListener  447 | 42 - org.springframework.osgi.extender - 1.2.1 | Stopping [org.springframework.osgi.extender] bundle v.[1.2.1]
+11:49:24,423 | INFO  |  Bundle Shutdown | TimerTaskExecutor                | heduling.timer.TimerTaskExecutor  179 | 37 - org.springframework.context - 3.0.5.RELEASE | Cancelling Timer
+11:49:24,498 | INFO  |  Bundle Shutdown | Activator                        | x.web.service.internal.Activator   93 | 67 - org.ops4j.pax.web.pax-web-runtime - 0.7.4 | Pax Web stopped
+11:49:24,499 | INFO  |  Bundle Shutdown | HttpServiceFactoryImpl           | .internal.HttpServiceFactoryImpl   40 | 67 - org.ops4j.pax.web.pax-web-runtime - 0.7.4 | Unbinding bundle: [org.apache.karaf.deployer.features_2.1.4 [27]]
+11:49:24,533 | INFO  |  Bundle Shutdown | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Stopping JMX OSGi agent
+11:49:24,534 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering org.osgi.jmx.framework.PackageStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=packageState,version=1.5
+11:49:24,534 | INFO  |  Bundle Shutdown | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering MBean with ObjectName [osgi.compendium:service=cm,version=1.3] for service with service.id [33]
+11:49:24,534 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering org.osgi.jmx.framework.FrameworkMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=framework,version=1.5
+11:49:24,534 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering org.osgi.jmx.framework.ServiceStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=serviceState,version=1.5
+11:49:24,534 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering org.osgi.jmx.service.cm.ConfigurationAdminMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.compendium:service=cm,version=1.3
+11:49:24,535 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering org.osgi.jmx.service.permissionadmin.PermissionAdminMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:service=permissionadmin,version=1.2
+11:49:24,535 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering org.osgi.jmx.framework.BundleStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=bundleState,version=1.5
+11:49:24,534 | INFO  |  Bundle Shutdown | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Unregistering MBean with ObjectName [osgi.core:service=permissionadmin,version=1.2] for service with service.id [3]
+11:49:24,539 | WARN  | rint Extender: 1 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.jaas.modules is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/jaas/v1.0.0))]
+11:49:24,541 | WARN  | rint Extender: 3 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.packages is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:24,543 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.commands is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:24,544 | WARN  | rint Extender: 1 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.dev is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]

Added: cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log.1
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log.1?rev=1077946&view=auto
==============================================================================
--- cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log.1 (added)
+++ cxf/trunk/rt/management-web/src/test/java/org/apache/cxf/management/web/logging/logs/karaf.log.1 Fri Mar  4 13:48:18 2011
@@ -0,0 +1,34 @@
+03-Mar-2011 11:49:12 org.apache.karaf.main.SimpleFileLock lock
+INFO: locking
+11:49:13,031 | INFO  | Event Dispatcher | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Starting JMX OSGi agent
+11:49:13,037 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.packages is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,102 | INFO  | Event Dispatcher | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering MBean with ObjectName [osgi.core:service=permissionadmin,version=1.2] for service with service.id [3]
+11:49:13,143 | INFO  | Event Dispatcher | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering MBean with ObjectName [osgi.compendium:service=cm,version=1.3] for service with service.id [33]
+11:49:13,153 | WARN  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | There are no MBean servers registred, can't register MBeans
+11:49:13,154 | WARN  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | There are no MBean servers registred, can't register MBeans
+11:49:13,233 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.commands is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,239 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.management is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0)), (&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0))]
+11:49:13,242 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.dev is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,272 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.jaas.modules is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0)), (&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0)), (&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/jaas/v1.0.0))]
+11:49:13,277 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.console is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0))]
+11:49:13,365 | WARN  | rint Extender: 3 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.admin.core is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0))]
+11:49:13,395 | WARN  | rint Extender: 3 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.admin.command is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,408 | WARN  | rint Extender: 1 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.osgi is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,553 | WARN  | rint Extender: 3 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.ssh is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,602 | WARN  | rint Extender: 2 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.features.command is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:13,635 | WARN  | rint Extender: 3 | BlueprintContainerImpl           | container.BlueprintContainerImpl  252 | 7 - org.apache.aries.blueprint - 0.2.0.incubating | Bundle org.apache.karaf.shell.log is waiting for namespace handlers [(&(objectClass=org.apache.aries.blueprint.NamespaceHandler)(osgi.service.blueprint.namespace=http://karaf.apache.org/xmlns/shell/v1.0.0))]
+11:49:14,206 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering org.osgi.jmx.framework.PackageStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=packageState,version=1.5
+11:49:14,208 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering org.osgi.jmx.framework.FrameworkMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=framework,version=1.5
+11:49:14,208 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering org.osgi.jmx.framework.ServiceStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=serviceState,version=1.5
+11:49:14,211 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering org.osgi.jmx.service.cm.ConfigurationAdminMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.compendium:service=cm,version=1.3
+11:49:14,211 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering org.osgi.jmx.service.permissionadmin.PermissionAdminMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:service=permissionadmin,version=1.2
+11:49:14,212 | INFO  | JMX OSGi Agent   | jmx                              | ?                                   ? | 20 - org.apache.aries.jmx - 0.2.0.incubating | Registering org.osgi.jmx.framework.BundleStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@c5c3ac with name osgi.core:type=bundleState,version=1.5
+11:49:14,931 | INFO  | rint Extender: 1 | SecurityUtils                    | e.sshd.common.util.SecurityUtils   80 | 28 - sshd-core - 0.4.0 | BouncyCastle not registered, using the default JCE provider
+11:49:16,463 | INFO  | Thread-4         | FeaturesServiceImpl              | res.internal.FeaturesServiceImpl  293 | 26 - org.apache.karaf.features.core - 2.1.4 | Bundles to refresh: 
+11:49:16,843 | INFO  | Thread-4         | ContextLoaderListener            | .activator.ContextLoaderListener  354 | 42 - org.springframework.osgi.extender - 1.2.1 | Starting [org.springframework.osgi.extender] bundle v.[1.2.1]
+11:49:17,068 | WARN  | Thread-4         | NamespaceManager                 | nternal.support.NamespaceManager  132 | 42 - org.springframework.osgi.extender - 1.2.1 | Bundle activemq-ra (org.apache.activemq.activemq-ra) cannot see class [org.springframework.beans.factory.xml.NamespaceHandlerResolver]; ignoring its namespace handlers
+11:49:17,172 | INFO  | Thread-4         | ExtenderConfiguration            | al.support.ExtenderConfiguration  150 | 42 - org.springframework.osgi.extender - 1.2.1 | No custom extender configuration detected; using defaults...
+11:49:17,184 | INFO  | Thread-4         | TimerTaskExecutor                | heduling.timer.TimerTaskExecutor  106 | 37 - org.springframework.context - 3.0.5.RELEASE | Initializing Timer
+11:49:17,497 | WARN  | Thread-4         | NamespaceManager                 | nternal.support.NamespaceManager  132 | 42 - org.springframework.osgi.extender - 1.2.1 | Bundle activemq-ra (org.apache.activemq.activemq-ra) cannot see class [org.springframework.beans.factory.xml.NamespaceHandlerResolver]; ignoring its namespace handlers
+11:49:17,535 | INFO  | Thread-4         | Activator                        | x.web.service.internal.Activator   80 | 67 - org.ops4j.pax.web.pax-web-runtime - 0.7.4 | Pax Web started
+11:49:17,775 | INFO  | Thread-11        | JettyServerImpl                  | e.jetty.internal.JettyServerImpl  100 | 68 - org.ops4j.pax.web.pax-web-jetty - 0.7.4 | Pax Web available at [0.0.0.0]:[8080]