Author: fmeschbe Date: Fri Jun 22 06:29:14 2012 New Revision: 1352777 URL: http://svn.apache.org/viewvc?rev=1352777&view=rev Log: SLING-2516 Request Performance Analysis helper along with Java application to display the collected data
Added: sling/trunk/contrib/extensions/reqanalyzer/ (with props) sling/trunk/contrib/extensions/reqanalyzer/pom.xml sling/trunk/contrib/extensions/reqanalyzer/src/ sling/trunk/contrib/extensions/reqanalyzer/src/main/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java Propchange: sling/trunk/contrib/extensions/reqanalyzer/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri Jun 22 06:29:14 2012 @@ -0,0 +1,4 @@ +.project +.classpath +.settings +target Added: sling/trunk/contrib/extensions/reqanalyzer/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/pom.xml?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/pom.xml (added) +++ sling/trunk/contrib/extensions/reqanalyzer/pom.xml Fri Jun 22 06:29:14 2012 @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>12</version> + </parent> + + <artifactId>org.apache.sling.reqanalyzer</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>Apache Sling Request Processing Analyzer</name> + <description> + Helps analyzing the processing times of Sling + requests. Writes the following information into + a log file: + - request start timestamp + - request end timestamp + - request URL, user, response status + - request progresstracker + </description> + + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/reqanalyzer</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/reqanalyzer</developerConnection> + <url>http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer</url> + </scm> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.sling</groupId> + <artifactId>maven-sling-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-Category>sling</Bundle-Category> + <Main-Class> + org.apache.sling.reqanalyzer.impl.gui.Main + </Main-Class> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>animal-sniffer-maven-plugin</artifactId> + <configuration> + <signature> + <groupId>org.codehaus.mojo.signature</groupId> + <artifactId>java16</artifactId> + <version>1.0</version> + </signature> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.engine</artifactId> + <version>2.2.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.api</artifactId> + <version>2.1.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.settings</artifactId> + <version>1.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>1.8.2</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,161 @@ +/* + * 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.sling.reqanalyzer.impl; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.Iterator; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Properties; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.Service; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper; +import org.apache.sling.engine.EngineConstants; +import org.apache.sling.settings.SlingSettingsService; +import org.osgi.framework.Constants; + +@Component(metatype = false) +@Service +@Properties({ @Property(name = EngineConstants.FILTER_NAME, value = "RequestAnalysisLogger"), + @Property(name = EngineConstants.SLING_FILTER_SCOPE, value = EngineConstants.FILTER_SCOPE_REQUEST), + @Property(name = Constants.SERVICE_RANKING, intValue = Integer.MAX_VALUE) }) +public class RequestAnalysisLogger implements Filter { + + @Reference + private SlingSettingsService settings; + + private BufferedWriter logFile; + + @SuppressWarnings("unused") + @Activate + private void activate() throws IOException { + final File logFile = new File(settings.getSlingHomePath(), "logs/requesttracker.txt"); + logFile.getParentFile().mkdirs(); + final FileOutputStream out = new FileOutputStream(logFile, true); + this.logFile = new BufferedWriter(new OutputStreamWriter(out, "UTF-8")); + } + + @SuppressWarnings("unused") + @Deactivate + private void deactivate() throws IOException { + if (this.logFile != null) { + this.logFile.close(); + this.logFile = null; + } + } + + public void init(FilterConfig filterConfig) throws ServletException { + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException { + + if (request instanceof SlingHttpServletRequest) { + final long start = System.currentTimeMillis(); + final AnylserSlingHttpServletResponse slingRes = new AnylserSlingHttpServletResponse( + (SlingHttpServletResponse) response); + try { + chain.doFilter(request, response); + } finally { + final long end = System.currentTimeMillis(); + final SlingHttpServletRequest slingReq = (SlingHttpServletRequest) request; + + StringBuilder pw = new StringBuilder(1024); + pw.append(String.format(":%d:%d:%s:%s:%s:%d%n", start, (end - start), slingReq.getMethod(), + slingReq.getRequestURI(), slingRes.getContentType(), slingRes.getStatus())); + + final Iterator<String> entries = slingReq.getRequestProgressTracker().getMessages(); + while (entries.hasNext()) { + pw.append('!').append(entries.next()); + } + + BufferedWriter out = this.logFile; + if (out != null) { + out.write(pw.toString()); + out.flush(); + } + } + } else { + chain.doFilter(request, response); + } + } + + public void destroy() { + } + + private static class AnylserSlingHttpServletResponse extends SlingHttpServletResponseWrapper { + + private int status = 200; + + public AnylserSlingHttpServletResponse(SlingHttpServletResponse wrappedResponse) { + super(wrappedResponse); + } + + public int getStatus() { + return status; + } + + @Override + public void setStatus(int sc) { + this.status = sc; + super.setStatus(sc); + } + + @Override + public void setStatus(int sc, String sm) { + this.status = sc; + super.setStatus(sc, sm); + } + + @Override + public void sendError(int sc) throws IOException { + this.status = sc; + super.sendError(sc); + } + + @Override + public void sendError(int sc, String msg) throws IOException { + this.status = sc; + super.sendError(sc, msg); + } + + @Override + public void sendRedirect(String location) throws IOException { + this.status = HttpServletResponse.SC_FOUND; + super.sendRedirect(location); + } + } +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,59 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +import java.awt.Dimension; +import java.awt.GraphicsEnvironment; +import java.awt.Toolkit; +import java.io.File; +import java.io.IOException; + +public class Main { + + public static void main(String[] args) throws IOException { + if (GraphicsEnvironment.isHeadless()) { + System.err.println("Cannot run in headless mode"); + System.exit(1); + } + + if (args.length == 0) { + System.err.println("Missing argument <file>"); + System.exit(1); + } + + File file = new File(args[0]); + if (!file.canRead()) { + System.err.println("Cannot read from file " + file); + System.exit(1); + } + + final int limit; + if (args.length >= 2) { + limit = Integer.parseInt(args[1]); + } else { + limit = Integer.MAX_VALUE; + } + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + MainFrame frame = new MainFrame(file, limit, screenSize); + frame.setVisible(true); + } + +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,82 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextPane; +import javax.swing.ListSelectionModel; +import javax.swing.table.JTableHeader; + +public class MainFrame extends JFrame { + + private static final long serialVersionUID = 1L; + + private static final String MAIN_Y = "main.y"; + private static final String MAIN_X = "main.x"; + private static final String MAIN_HEIGHT = "main.height"; + private static final String MAIN_WIDTH = "main.width"; + private static final String MAIN_COLS = "main.cols"; + + public MainFrame(final File file, final int limit, final Dimension screenSize) throws FileNotFoundException, + IOException { + + JTextPane text = Util.showStartupDialog("Reading from " + file, screenSize); + + final RequestTrackerFile dm = new RequestTrackerFile(file, limit, text); + + final JTable table = new JTable(dm); + table.setAutoCreateRowSorter(true); + table.setGridColor(Color.GRAY); + table.setShowGrid(true); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table.setRowSelectionAllowed(true); + table.setTableHeader(new JTableHeader(table.getColumnModel())); + Util.setupColumnWidths(table.getColumnModel(), MAIN_COLS); +// table.setFont(new Font("Monospaced", table.getFont().getStyle(), table.getFont().getSize())); + table.getSelectionModel().addListSelectionListener(new RequestListSelectionListener(this, table, screenSize)); + + add(new JScrollPane(table)); + + setTitle(file.getPath()); + + // exit the application if the main frame is closed + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + + // setup location and size and ensure updating preferences + Util.setupComponentLocationSize(this, MAIN_X, MAIN_Y, MAIN_WIDTH, MAIN_HEIGHT, (int) screenSize.getWidth() / 4, + 0, (int) screenSize.getWidth() / 2, (int) screenSize.getHeight() / 4); + + Util.disposeStartupDialog(text); + } +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,107 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; + +import javax.swing.JDialog; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableModel; + +public class RequestListSelectionListener implements ListSelectionListener { + + private static final String REQUEST_Y = "request.y"; + private static final String REQUEST_X = "request.x"; + private static final String REQUEST_HEIGHT = "request.height"; + private static final String REQUEST_WIDTH = "request.width"; + private static final String REQUEST_COLS = "request.cols"; + + private final Window parent; + private final JTable table; + private final Dimension screenSize; + + private JTable dataField = null; + + public RequestListSelectionListener(final Window parent, final JTable table, final Dimension screenSize) { + this.parent = parent; + this.table = table; + this.screenSize = screenSize; + } + + public void valueChanged(ListSelectionEvent e) { + if (!e.getValueIsAdjusting()) { + ListSelectionModel lsm = (ListSelectionModel) e.getSource(); + int idx = lsm.getMinSelectionIndex(); + if (idx >= 0) { + try { + idx = table.getRowSorter().convertRowIndexToModel(idx); + TableModel tm = ((RequestTrackerFile) table.getModel()).getData(idx); + if (dataField == null) { + dataField = new JTable(); + dataField.setAutoCreateRowSorter(true); + dataField.setGridColor(Color.GRAY); + dataField.setShowGrid(true); + dataField.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + dataField.setRowSelectionAllowed(true); + dataField.setTableHeader(new JTableHeader(dataField.getColumnModel())); + dataField.setFont(new Font("Monospaced", dataField.getFont().getStyle(), dataField.getFont().getSize())); + dataField.setShowHorizontalLines(false); +// dataField.setIntercellSpacing(new Dimension(3, 5)); + + JDialog d = new JDialog(this.parent); + d.add(new JScrollPane(dataField)); + + d.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + dataField = null; + } + }); + + // setup location and size and ensure updating preferences + Util.setupComponentLocationSize(d, REQUEST_X, REQUEST_Y, REQUEST_WIDTH, REQUEST_HEIGHT, + (int) screenSize.getWidth() / 4, (int) screenSize.getHeight() / 4, + (int) screenSize.getWidth() / 2, (int) screenSize.getHeight() / 2); + + d.setVisible(true); + } + + dataField.setModel(tm); + + Util.setupColumnWidths(dataField.getColumnModel(), REQUEST_COLS); + + } catch (IOException e1) { + // ignore + } + } + } + } + +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,98 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +import java.util.ArrayList; + +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; + +public class RequestTableModel implements TableModel { + + private final ArrayList<Object[]> rows = new ArrayList<Object[]>(); + + private long previousStamp; + + void addRow(String row) { + // split row: "%1$7d (%2$tF %2$tT) %3$s%n + + final String stampS = row.substring(0, 7); + final int endTimeStamp = row.indexOf(')'); + final String message = row.substring(endTimeStamp+2); + + long stamp = Long.parseLong(stampS.trim()); + long delta = stamp - this.previousStamp; + this.previousStamp = stamp; + + final Object[] rowValue = new Object[]{ stamp, delta, message }; + this.rows.add(rowValue); + } + + public int getRowCount() { + return rows.size(); + } + + public int getColumnCount() { + return 3; + } + + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return "Timestamp"; + case 1: + return "Delta"; + case 2: + return "Message"; + default: + throw new IllegalArgumentException("columnIndex=" + columnIndex); + } + } + + public Class<?> getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return Long.class; + case 1: + return Long.class; + case 2: + return String.class; + default: + throw new IllegalArgumentException("columnIndex=" + columnIndex); + } + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + Object[] row = rows.get(rowIndex); + return row[columnIndex]; + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + } + + public void addTableModelListener(TableModelListener l) { + } + + public void removeTableModelListener(TableModelListener l) { + } +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,105 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JTextPane; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; + +public class RequestTrackerFile implements TableModel { + + private final RandomAccessFile raFile; + private final List<RequestTrackerFileEntry> entries; + + RequestTrackerFile(File file, int limit, JTextPane text) throws FileNotFoundException, IOException { + this.raFile = new RandomAccessFile(file, "r"); + this.entries = new ArrayList<RequestTrackerFileEntry>(); + String line; + for (int i = 0; i < limit && (line = this.raFile.readLine()) != null; ) { + if (line.charAt(0) == ':') { + try { + text.setText(line); + RequestTrackerFileEntry entry = new RequestTrackerFileEntry(line, this.raFile.getFilePointer()); + this.entries.add(entry); + i++; + } catch (Exception e) { + System.err.println(e); + e.printStackTrace(System.err); + break; + } + } + } + } + + TableModel getData(final int rowIndex) throws IOException { + final RequestTrackerFileEntry entry = this.entries.get(rowIndex); + final long offset = entry.getOffset(); + RequestTableModel rtm = new RequestTableModel(); + this.raFile.seek(offset); + String line; + while ((line = raFile.readLine()) != null && line.charAt(0) == '!') { + rtm.addRow(line.substring(1)); + } + return rtm; + } + + public int getRowCount() { + return this.entries.size(); + } + + public int getColumnCount() { + return RequestTrackerFileEntry.getColumnCount(); + } + + public String getColumnName(int columnIndex) { + return RequestTrackerFileEntry.getColumnName(columnIndex); + } + + public Class<?> getColumnClass(int columnIndex) { + return RequestTrackerFileEntry.getColumnClass(columnIndex); + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + RequestTrackerFileEntry entry = this.entries.get(rowIndex); + return entry.getField(columnIndex); + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + throw new UnsupportedOperationException("setValue"); + } + + public void addTableModelListener(TableModelListener l) { + // not really ... + } + + public void removeTableModelListener(TableModelListener l) { + // not really ... + } +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,118 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +public class RequestTrackerFileEntry { + + /* + * Request Tracker Info Line: + * + * :1340236961239:235:GET:/healthck/healthck.html:text/html; charset=UTF-8:200 + */ + + private final long start; + private final long duration; + private final String method; + private final String url; + private final String contentType; + private final int status; + private final long offset; + + static int getColumnCount() { + return 6; + } + + static String getColumnName(final int idx) { + switch (idx) { + case 0: + return "Start"; + case 1: + return "Duration"; + case 2: + return "Method"; + case 3: + return "URL"; + case 4: + return "Content Type"; + case 5: + return "Status"; + default: + throw new IllegalArgumentException("Unknown field index " + idx); + } + } + + static Class<?> getColumnClass(final int idx) { + switch (idx) { + case 0: + return Long.class; + case 1: + return Long.class; + case 2: + return String.class; + case 3: + return String.class; + case 4: + return String.class; + case 5: + return Integer.class; + default: + throw new IllegalArgumentException("Unknown field index " + idx); + } + } + + RequestTrackerFileEntry(final String statusLine, final long offset) { + String[] parts = statusLine.split(":"); + this.start = Long.parseLong(parts[1]); + this.duration = Long.parseLong(parts[2]); + this.method = parts[3]; + + String url = parts[4]; + for (int i = 5; i < parts.length - 2; i++) { + url += ":" + parts[i]; + } + this.url = url; + + this.contentType = parts[parts.length-2]; + this.status = Integer.parseInt(parts[parts.length-1]); + this.offset = offset; + } + + Object getField(final int idx) { + switch (idx) { + case 0: + return start; + case 1: + return duration; + case 2: + return method; + case 3: + return url; + case 4: + return contentType; + case 5: + return status; + default: + throw new IllegalArgumentException("Unknown field index " + idx); + } + } + + long getOffset() { + return offset; + } +} Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java?rev=1352777&view=auto ============================================================================== --- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java (added) +++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java Fri Jun 22 06:29:14 2012 @@ -0,0 +1,177 @@ +/* + * 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.sling.reqanalyzer.impl.gui; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; + +import javax.swing.JDialog; +import javax.swing.JTextPane; +import javax.swing.table.TableColumnModel; + +public class Util { + + private Util() { + } + + static JTextPane showStartupDialog(final String title, final Dimension screenSize) { + JTextPane text = new JTextPane(); + text.setText("..."); + + JDialog d = new JDialog((Window) null); + d.setTitle(title); + d.add(text); + d.setSize((int) screenSize.getWidth() / 2, 30); + d.setLocation((int) screenSize.getWidth() / 4, (int) screenSize.getHeight() / 2 - 15); + d.setVisible(true); + + return text; + } + + static void disposeStartupDialog(final Component comp) { + Container parent = comp.getParent(); + while (parent != null && !(parent instanceof Window)) { + parent = parent.getParent(); + } + if (parent instanceof Window) { + ((Window) parent).dispose(); + } + } + + static void setupComponentLocationSize(final Component comp, final String propX, final String propY, + final String propWidth, final String propHeight, final int defaultX, final int defaultY, + final int defaultWidth, final int defaultHeight) { + + comp.setLocation(getPreference(propX, defaultY), getPreference(propY, defaultX)); + comp.setSize(getPreference(propWidth, defaultWidth), getPreference(propHeight, defaultHeight)); + + comp.addComponentListener(new ComponentAdapter() { + @Override + public void componentMoved(ComponentEvent e) { + setPreference(propX, e.getComponent().getX(), false); + setPreference(propY, e.getComponent().getY(), true); + } + + @Override + public void componentResized(ComponentEvent e) { + setPreference(propWidth, e.getComponent().getWidth(), false); + setPreference(propHeight, e.getComponent().getHeight(), true); + } + }); + } + + static void setupColumnWidths(final TableColumnModel tcm, final String propertyName) { + PropertyChangeListener pcl = new PropertyChangeListener() { + private final String pclPropName = propertyName; + private final TableColumnModel pclTcm = tcm; + + public void propertyChange(PropertyChangeEvent evt) { + if ("width".equals(evt.getPropertyName())) { + int[] colWidths = new int[pclTcm.getColumnCount()]; + for (int i = 0; i < colWidths.length; i++) { + colWidths[i] = pclTcm.getColumn(i).getWidth(); + } + setPreference(pclPropName, colWidths, true); + } + } + }; + + int[] colWidths = getPreference(propertyName, new int[0]); + for (int i = 0; i < colWidths.length && i < tcm.getColumnCount(); i++) { + tcm.getColumn(i).setPreferredWidth(colWidths[i]); + } + for (int i = 0; i < tcm.getColumnCount(); i++) { + tcm.getColumn(i).addPropertyChangeListener(pcl); + } + } + + static void setPreference(final String name, final Object value, final boolean flush) { + Preferences prefs = getPreferences(); + try { + prefs.sync(); + if (value instanceof Long) { + prefs.putLong(name, (Long) value); + } else if (value instanceof Integer) { + prefs.putInt(name, (Integer) value); + } else if (value instanceof int[]) { + String string = null; + for (int val : (int[]) value) { + if (string == null) { + string = String.valueOf(val); + } else { + string += "," + val; + } + } + prefs.put(name, string); + } else if (value != null) { + prefs.put(name, value.toString()); + } + + if (flush) { + prefs.flush(); + } + } catch (BackingStoreException ioe) { + // ignore + } + } + + static int getPreference(final String name, final int defaultValue) { + Preferences prefs = getPreferences(); + try { + prefs.sync(); + return prefs.getInt(name, defaultValue); + } catch (BackingStoreException ioe) { + // ignore + } + return defaultValue; + } + + static int[] getPreference(final String name, final int[] defaultValues) { + Preferences prefs = getPreferences(); + try { + prefs.sync(); + String value = prefs.get(name, null); + if (value != null) { + String[] values = value.split(","); + int[] result = new int[values.length]; + for (int i = 0; i < values.length; i++) { + result[i] = Integer.parseInt(values[i]); + } + return result; + } + } catch (BackingStoreException ioe) { + // ignore + } catch (NumberFormatException nfe) { + // ignore + } + return defaultValues; + } + + static Preferences getPreferences() { + return Preferences.userNodeForPackage(Util.class); + } +}