You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/10/18 23:24:54 UTC
[sling-org-apache-sling-reqanalyzer] 01/18: SLING-2516 Request
Performance Analysis helper along with Java application to display the
collected data
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-reqanalyzer.git
commit 51b2b9be95e71c226871c4047c78c78c97523c6e
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Fri Jun 22 06:29:14 2012 +0000
SLING-2516 Request Performance Analysis helper along with Java application to display the collected data
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1352777 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 141 ++++++++++++++++
.../reqanalyzer/impl/RequestAnalysisLogger.java | 161 +++++++++++++++++++
.../apache/sling/reqanalyzer/impl/gui/Main.java | 59 +++++++
.../sling/reqanalyzer/impl/gui/MainFrame.java | 82 ++++++++++
.../impl/gui/RequestListSelectionListener.java | 107 +++++++++++++
.../reqanalyzer/impl/gui/RequestTableModel.java | 98 ++++++++++++
.../reqanalyzer/impl/gui/RequestTrackerFile.java | 105 ++++++++++++
.../impl/gui/RequestTrackerFileEntry.java | 118 ++++++++++++++
.../apache/sling/reqanalyzer/impl/gui/Util.java | 177 +++++++++++++++++++++
9 files changed, 1048 insertions(+)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0e99218
--- /dev/null
+++ b/pom.xml
@@ -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>
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java b/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java
new file mode 100644
index 0000000..bcf98c4
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java
@@ -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);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java
new file mode 100644
index 0000000..c0efcca
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java
@@ -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);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java
new file mode 100644
index 0000000..7feb4f1
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java
@@ -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);
+ }
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java
new file mode 100644
index 0000000..1c12ed2
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestListSelectionListener.java
@@ -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
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java
new file mode 100644
index 0000000..078bdbe
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTableModel.java
@@ -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) {
+ }
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java
new file mode 100644
index 0000000..7d20bec
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFile.java
@@ -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 ...
+ }
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java
new file mode 100644
index 0000000..744e3d5
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/RequestTrackerFileEntry.java
@@ -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;
+ }
+}
diff --git a/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java
new file mode 100644
index 0000000..4f10539
--- /dev/null
+++ b/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Util.java
@@ -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);
+ }
+}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.