From 0cfaaf9bbce0698a85c0629efde4c176471e9dee Mon Sep 17 00:00:00 2001 From: Arnaud Date: Tue, 17 Dec 2013 19:21:22 +0100 Subject: [PATCH] [FEATURE] Add stat packages --- .../plantuml/pstat/LogCallback.java | 39 +++ .../plantuml/pstat/StatSxServlet.java | 66 ++++ .../net/sourceforge/plantuml/pstat/Stats.java | 312 +++++++++++++++++ .../plantuml/pstat/WriterOutputStream.java | 50 +++ .../plantuml/pstat/event/StatEvent.java | 318 ++++++++++++++++++ .../pstat/event/StatEventAdminSaveLog.java | 64 ++++ .../pstat/event/StatEventAdminStart.java | 51 +++ .../pstat/event/StatEventAdminStop.java | 51 +++ .../pstat/event/StatEventFileIterator.java | 44 +++ .../event/StatEventFileIteratorSimple.java | 78 +++++ .../pstat/event/StatEventFileIteratorZip.java | 89 +++++ .../pstat/event/StatEventHtmlCreate.java | 71 ++++ .../pstat/event/StatEventHtmlLoadImage.java | 85 +++++ .../pstat/event/StatEventHtmlLoadPage.java | 86 +++++ .../pstat/event/StatEventImageGeneration.java | 100 ++++++ .../plantuml/pstat/event/UAParser.java | 65 ++++ .../plantuml/pstat/graph/Chart.java | 285 ++++++++++++++++ .../plantuml/pstat/graph/ChartProducer.java | 135 ++++++++ .../plantuml/pstat/graph/Curve.java | 156 +++++++++ .../plantuml/pstat/graph/HistoList.java | 174 ++++++++++ .../plantuml/pstat/graph/Histogram.java | 153 +++++++++ .../pstat/graph/HistogramBuilder.java | 66 ++++ .../plantuml/pstat/graph/MutableInteger.java | 42 +++ .../plantuml/pstat/graph/NiceNumber.java | 47 +++ .../plantuml/pstat/graph/NiceNumberTest.java | 95 ++++++ .../pstat/tick/CounterSetInteger.java | 56 +++ .../plantuml/pstat/tick/CounterSetLoad.java | 57 ++++ .../plantuml/pstat/tick/CounterSetString.java | 146 ++++++++ .../plantuml/pstat/tick/DailyStat.java | 42 +++ .../sourceforge/plantuml/pstat/tick/Day.java | 56 +++ .../plantuml/pstat/tick/GraphData.java | 152 +++++++++ .../pstat/tick/GraphDataLongTerm.java | 53 +++ .../plantuml/pstat/tick/TickBrowser.java | 87 +++++ .../pstat/tick/TickCollectionFilterTime.java | 48 +++ .../plantuml/pstat/tick/TickDatabase.java | 97 ++++++ .../pstat/tick/TickFilterIterator.java | 68 ++++ .../pstat/tick/TickImageGeneration.java | 102 ++++++ .../plantuml/pstat/time/DateManager.java | 40 +++ .../plantuml/pstat/time/DateManagerDaily.java | 55 +++ .../pstat/time/DateManagerHourly.java | 56 +++ .../pstat/time/DateManagerMinutely.java | 56 +++ .../pstat/time/DateManagerMonthly.java | 52 +++ .../plantuml/pstat/time/DateManagerYear.java | 44 +++ 43 files changed, 3989 insertions(+) create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/LogCallback.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/StatSxServlet.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/Stats.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/WriterOutputStream.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEvent.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminSaveLog.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStart.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStop.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIterator.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorSimple.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorZip.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlCreate.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadImage.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadPage.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/StatEventImageGeneration.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/event/UAParser.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/Chart.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/ChartProducer.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/Curve.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/HistoList.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/Histogram.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/HistogramBuilder.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/MutableInteger.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumber.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumberTest.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetInteger.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetLoad.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetString.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/DailyStat.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/Day.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/GraphData.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/GraphDataLongTerm.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/TickBrowser.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/TickCollectionFilterTime.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/TickDatabase.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/TickFilterIterator.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/tick/TickImageGeneration.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/time/DateManager.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerDaily.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerHourly.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMinutely.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMonthly.java create mode 100644 src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerYear.java diff --git a/src/main/java/net/sourceforge/plantuml/pstat/LogCallback.java b/src/main/java/net/sourceforge/plantuml/pstat/LogCallback.java new file mode 100644 index 0000000..be0681c --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/LogCallback.java @@ -0,0 +1,39 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat; + +import javax.servlet.http.HttpServletRequest; + +public interface LogCallback { + + public void logHtmlCreate(String token, long date0, long date1, String encoded, HttpServletRequest request); + + public void logHtmlLoadPage(HttpServletRequest request, long date0, String start, String end, String token, + String width, String height); + + public void logHtmlLoadImage(HttpServletRequest request, long date0, String start, String end, String token, + String width, String height); + + public void logImageGeneration(HttpServletRequest request, long date0, long date1, String type); +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/StatSxServlet.java b/src/main/java/net/sourceforge/plantuml/pstat/StatSxServlet.java new file mode 100644 index 0000000..d6e3f58 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/StatSxServlet.java @@ -0,0 +1,66 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@SuppressWarnings("serial") +public class StatSxServlet extends HttpServlet { + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + String token = request.getParameter("t"); + String start = request.getParameter("s"); + String page = request.getParameter("p"); + String image = request.getParameter("i"); + String width = request.getParameter("w"); + String height = request.getParameter("h"); + + if (page != null) { + Stats.getInstance().logHtmlLoadPage(request, System.currentTimeMillis(), start, page, token, width, height); + } + if (image != null) { + Stats.getInstance().logHtmlLoadImage(request, System.currentTimeMillis(), start, image, token, width, + height); + } + + // System.err.println("get sx1 " + token + " start=" + start + " page=" + page + " image=" + image); + } + + @Override + public void destroy() { + super.destroy(); + Stats.getInstance().destroy(); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, + IOException { + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/Stats.java b/src/main/java/net/sourceforge/plantuml/pstat/Stats.java new file mode 100644 index 0000000..64c388e --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/Stats.java @@ -0,0 +1,312 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat; + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.Locale; +import java.util.Random; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import javax.servlet.http.HttpServletRequest; + +import net.sourceforge.plantuml.pstat.event.StatEvent; +import net.sourceforge.plantuml.pstat.event.StatEventAdminStart; +import net.sourceforge.plantuml.pstat.event.StatEventAdminStop; +import net.sourceforge.plantuml.pstat.event.StatEventFileIterator; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlCreate; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlLoadImage; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlLoadPage; +import net.sourceforge.plantuml.pstat.event.StatEventImageGeneration; +import net.sourceforge.plantuml.pstat.graph.Curve; +import net.sourceforge.plantuml.pstat.tick.GraphData; +import net.sourceforge.plantuml.pstat.tick.GraphDataLongTerm; +import net.sourceforge.plantuml.pstat.tick.TickDatabase; + +public class Stats implements LogCallback { + + public static final boolean USE_STATS = true; + + static class Mem { + public Mem(StatEvent ev) { + totalMemory = (int) (ev.getTotalMemory() / 1024L / 1024L); + freeMemory = (int) (ev.getFreeMemory() / 1024L / 1024L); + activeCount = ev.getActiveCount(); + time = ev.getStartServerTime(); + + } + + final private long time; + final private int freeMemory; + final private int totalMemory; + final private int activeCount; + } + + private final static Stats singleton = new Stats(); + + private final LinkedBlockingDeque events = new LinkedBlockingDeque(); + private final LinkedBlockingDeque memories = new LinkedBlockingDeque(); + private final TickDatabase tickDatabase = USE_STATS ? new TickDatabase() : null; + + public GraphData getGraphData() { + return tickDatabase == null ? new GraphData() : tickDatabase.getGraphData(); + } + + public GraphDataLongTerm getGraphDataLongTerm() { + return tickDatabase == null ? new GraphDataLongTerm() : tickDatabase.getGraphDataLongTerm(); + } + + private static final Random rnd = new Random(); + + public String getNewToken(long now) { + final String t = Integer.toString((int) (now / 1000L), 36) + + Long.toString(Math.abs(rnd.nextLong()), 36).substring(1); + return t; + } + + public static File getSavedFile() { + return new File(getSavedFileName() + ".pat"); + } + + public static String getSavedFileName() { + final DateFormat df = new SimpleDateFormat("yyyy_MM", Locale.US); + return "pdata" + df.format(new Date()); + } + + public static String getPreviousFileName() { + final DateFormat df = new SimpleDateFormat("yyyy_MM", Locale.US); + final String cname = df.format(new Date()); + int y = Integer.parseInt(cname.substring(0, 4)); + int m = Integer.parseInt(cname.substring(5, 7)); + m--; + if (m == 0) { + y--; + m = 12; + } + return "pdata" + String.format("%04d", y) + "_" + String.format("%02d", m); + } + + private Stats() { + final Thread th = new Thread() { + public void run() { + fileAccess.lock(); + try { + reload(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + fileAccess.unlock(); + } + } + }; + addEvent(new StatEventAdminStart()); + th.start(); + } + + private final Lock fileAccess = new ReentrantLock(); + + private void reload() throws IOException { + reload(getSavedFile()); + final String cur = getSavedFileName(); + for (char c = 'a'; c < 'z'; c++) { + reload(cur + c); + } + final String prev = getPreviousFileName(); + reload(prev); + for (char c = 'a'; c < 'z'; c++) { + reload(prev + c); + } + reload("legacy2000"); + } + + private void reload(final String name) throws IOException { + File file = new File(name + ".pat"); + if (file.exists() == false) { + file = new File(name + ".pat.gz"); + } + if (file.exists() == false) { + file = new File(name + ".zip"); + } + reload(file); + } + + private void reload(final File file) throws IOException { + if (file.exists() == false) { + return; + } + StatEventFileIterator it = null; + try { + it = StatEventFileIterator.fromFile(file); + reload(it); + } finally { + if (it != null) { + it.close(); + } + } + } + + private void reload(StatEventFileIterator it) { + while (it.hasNext()) { + final StatEvent ev = it.next(); + updateStats(ev); + Thread.yield(); + } + } + + public static Stats getInstance() { + return singleton; + } + + private void addEvent(final StatEvent ev) { + updateStats(ev); + events.add(ev); + memories.add(new Mem(ev)); + while (memories.size() > 100) { + final Iterator it = memories.iterator(); + it.next(); + it.remove(); + } + + if (fileAccess.tryLock()) { + try { + saveEvents(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + fileAccess.unlock(); + } + } + } + + public void destroy() { + System.err.println("CALLING DESTROY"); + addEvent(new StatEventAdminStop()); + if (fileAccess.tryLock()) { + try { + saveEvents(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + fileAccess.unlock(); + } + } + } + + private void saveEvents() throws IOException { + final File saveFile = getSavedFile(); + // final long startSave = System.currentTimeMillis(); + DataOutputStream oos = null; + try { + oos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(saveFile, true), 1024 * 50)); + for (Iterator it = events.iterator(); it.hasNext();) { + final StatEvent event = it.next(); + event.save(oos); + it.remove(); + // nbSave++; + } + } finally { + if (oos != null) { + oos.close(); + } + } + } + + public void logHtmlCreate(String token, long date0, long date1, String encoded, HttpServletRequest request) { + final StatEvent event = new StatEventHtmlCreate(request, date0, date1, token, encoded); + addEvent(event); + } + + public void logHtmlLoadPage(HttpServletRequest request, long date0, String start, String end, String token, + String width, String height) { + final long start_ = parseSecureLong(start); + final long end_ = parseSecureLong(end); + final int width_ = parseSecureInt(width); + final int height_ = parseSecureInt(height); + final StatEventHtmlLoadPage event = new StatEventHtmlLoadPage(request, date0, start_, end_, token, width_, + height_); + addEvent(event); + + } + + public void logHtmlLoadImage(HttpServletRequest request, long date0, String start, String end, String token, + String width, String height) { + final long start_ = parseSecureLong(start); + final long end_ = parseSecureLong(end); + final int width_ = parseSecureInt(width); + final int height_ = parseSecureInt(height); + final StatEventHtmlLoadImage event = new StatEventHtmlLoadImage(request, date0, start_, end_, token, width_, + height_); + addEvent(event); + } + + public void logImageGeneration(HttpServletRequest request, long date0, long date1, String type) { + final StatEventImageGeneration event = new StatEventImageGeneration(request, date0, date1, type); + addEvent(event); + } + + private int parseSecureInt(String s) { + if (s != null && s.matches("\\d+")) { + return Integer.parseInt(s); + } + return 0; + } + + private long parseSecureLong(String s) { + if (s != null && s.matches("\\d+")) { + return Long.parseLong(s); + } + return 0; + } + + private void updateStats(final StatEvent ev) { + if (USE_STATS) { + tickDatabase.updateStats(ev); + } + } + + public Curve memories(double height, double singleBarWidth, int fontSize) { + final Curve result = new Curve(height, singleBarWidth, fontSize); + for (Mem mem : memories) { + result.addData(new Date(mem.time).toString(), mem.totalMemory, mem.freeMemory); + } + return result; + } + + public Curve threads(double height, double singleBarWidth, int fontSize) { + final Curve result = new Curve(height, singleBarWidth, fontSize); + for (Mem mem : memories) { + result.addData(new Date(mem.time).toString(), mem.activeCount); + } + return result; + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/WriterOutputStream.java b/src/main/java/net/sourceforge/plantuml/pstat/WriterOutputStream.java new file mode 100644 index 0000000..e338851 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/WriterOutputStream.java @@ -0,0 +1,50 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +public class WriterOutputStream extends OutputStream { + + final Writer pw; + + public WriterOutputStream(Writer pw) { + this.pw = pw; + } + + @Override + public void write(int data) throws IOException { + pw.write(data); + + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + final String s = new String(b, off, len); + pw.write(s); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEvent.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEvent.java new file mode 100644 index 0000000..f816cb5 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEvent.java @@ -0,0 +1,318 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.maxmind.geoip.LookupService; + +public abstract class StatEvent { + + private final int byteHeader; + private final long serverTime; + private final Map header = new HashMap(); + private final String ipClient; + + private final int activeCount; + private final long freeMemory; + private final long totalMemory; + + private static final UAParser uaParser = new UAParser(); + private static final LookupService countryService = initCountryService(); + + private static LookupService initCountryService() { + try { + return new LookupService("GeoIP.dat", LookupService.GEOIP_MEMORY_CACHE); + } catch (FileNotFoundException e) { + System.err.println("path=" + new File("GeoIP.dat").getAbsolutePath() + " not found"); + return null; + } catch (IOException e) { + System.err.println("path=" + new File("GeoIP.dat").getAbsolutePath()); + e.printStackTrace(); + return null; + } + } + + synchronized public void save(DataOutputStream os) throws IOException { + os.write(0x43); + os.writeInt(activeCount); + os.writeLong(freeMemory); + os.writeLong(totalMemory); + os.write(byteHeader); + os.writeLong(serverTime); + writeStringSecure(os, ipClient); + for (Map.Entry ent : header.entrySet()) { + writeStringSecure(os, ent.getKey()); + writeStringSecure(os, ent.getValue()); + } + writeStringSecure(os, ""); + saveSuppData(os); + } + + public static StatEvent read(DataInputStream is) throws IOException { + final int sign = is.read(); + if (sign == -1) { + return null; + } + final int activeCount; + final long freeMemory; + final long totalMemory; + if (sign == 0x42) { + activeCount = 0; + freeMemory = 0; + totalMemory = 0; + } else if (sign == 0x43) { + activeCount = is.readInt(); + freeMemory = is.readLong(); + totalMemory = is.readLong(); + } else { + throw new IOException("No 0x42 header found"); + } + final int byteHeader = is.read(); + final long serverTime = is.readLong(); + final String ipClient = is.readUTF(); + final Map header = new HashMap(); + while (true) { + final String key = is.readUTF(); + if (key.length() == 0) { + break; + } + final String value = is.readUTF(); + header.put(key.toLowerCase(), value); + } + switch (byteHeader) { + case 0x51: + return new StatEventAdminStart(is, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + case 0x52: + return new StatEventAdminStop(is, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + case 0x53: + return new StatEventAdminSaveLog(is, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + case 0x43: + return new StatEventHtmlCreate(is, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + case 0x44: + return new StatEventHtmlLoadPage(is, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + case 0x45: + return new StatEventHtmlLoadImage(is, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + case 0x46: + case 0x47: + return new StatEventImageGeneration(byteHeader, is, serverTime, ipClient, header, activeCount, freeMemory, + totalMemory); + } + throw new IOException("Unknown header " + byteHeader); + } + + protected abstract void saveSuppData(DataOutputStream os) throws IOException; + + public StatEvent(int byteHeader, long serverTime, HttpServletRequest request) { + this.byteHeader = byteHeader; + this.serverTime = serverTime; + this.activeCount = Thread.activeCount(); + this.freeMemory = Runtime.getRuntime().freeMemory(); + this.totalMemory = Runtime.getRuntime().totalMemory(); + + if (request != null) { + for (Enumeration foo = request.getHeaderNames(); foo.hasMoreElements();) { + String h = foo.nextElement().toString().toLowerCase(); + String v = request.getHeader(h); + header.put(h, v); + } + this.ipClient = request.getRemoteAddr(); + } else { + this.ipClient = ""; + } + } + + public StatEvent(int byteHeader, long serverTime, String ipClient, Map header, int activeCount, + long freeMemory, long totalMemory) { + this.byteHeader = byteHeader; + this.serverTime = serverTime; + this.ipClient = ipClient; + this.header.putAll(header); + this.activeCount = activeCount; + this.freeMemory = freeMemory; + this.totalMemory = totalMemory; + } + + @Override + public String toString() { + // System.err.println(header.keySet()); + // System.err.println(header); + final long f = freeMemory / 1024 / 1024; + final long t = totalMemory / 1024 / 1024; + return "{" + Integer.toHexString(byteHeader) + "} " + new Date(serverTime).toGMTString() + " " + f + "/" + t + + " " + activeCount + " " + ipClient + " {" + getAcceptLanguage() + "} {" + getCountry() + "} [" + + getRefererDetailed() + "] "; + } + + public String getAcceptLanguage() { + final String lang = header.get("accept-language"); + if (lang == null) { + return "??"; + } + if (lang.length() < 2) { + return "??"; + } + return lang.substring(0, 2); + } + + public String getHost() { + final String host = header.get("host"); + if (host == null) { + return "??"; + } + return host; + } + + public String getUserAgent() { + final String agent = header.get("user-agent"); + if (agent == null) { + return "??"; + } + return agent; + } + + public String getReferer() { + String agent = header.get("referer"); + if (agent == null) { + return "??"; + } + final int x = agent.indexOf('/', 9); + if (x == -1) { + return "??"; + } + agent = agent.substring(0, x); + if (agent.matches(".*\\.[a-z]{2,3}$")) { + return agent; + } + return "Other"; + } + + private String getRefererDetailed() { + String agent = header.get("referer"); + if (agent == null) { + return "None"; + } + final int x = agent.indexOf('/', 9); + if (x == -1) { + return "??"; + } + agent = agent.substring(0, x); + if (agent.matches(".*\\.[a-z]{2,3}$")) { + return agent; + } + // return "Other"; + return agent; + } + + public String getOperatingSystem() { + final String user = getUserAgent(); + if ("??".equals(user)) { + return "??"; + } + final String result = uaParser.getOperatingSystem(user); + if (result.startsWith("OS X")) { + return "OS X"; + } + if (result.startsWith("Android")) { + return "Android"; + } + if (result.startsWith("iOS")) { + return "iOS"; + } + return result; + } + + public String getBrowser() { + final String user = getUserAgent(); + if ("??".equals(user)) { + return "??"; + } + final String result = uaParser.getBrowser(user); + return result; + } + + public long getStartServerTime() { + return serverTime; + } + + protected Map getHeader() { + return Collections.unmodifiableMap(header); + } + + public String getIpClient() { + return ipClient; + } + + public String getCountry() { + if (countryService == null) { + return "Not loaded"; + } + if (ipClient == null) { + return "??"; + } + final String country = countryService.getCountry(ipClient).getName(); + if ("N/A".equals(country)) { + return "??"; + } + return country; + } + + final protected void writeStringSecure(DataOutputStream oos, String s) throws IOException { + if (s == null) { + s = ""; + } + oos.writeUTF(s); + } + + final protected String shorten(String s) { + if (s.length() > 20) { + return s.substring(0, 20) + "..."; + } + return s; + } + + public final int getActiveCount() { + return activeCount; + } + + public final long getFreeMemory() { + return freeMemory; + } + + public final long getTotalMemory() { + return totalMemory; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminSaveLog.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminSaveLog.java new file mode 100644 index 0000000..ae4fb6a --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminSaveLog.java @@ -0,0 +1,64 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +public class StatEventAdminSaveLog extends StatEvent { + + private final int saveDuration; + private final int nbSaved; + private final int nbRemainingAfterSave; + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + os.writeInt(saveDuration); + os.writeInt(nbSaved); + os.writeInt(nbRemainingAfterSave); + } + + public StatEventAdminSaveLog(int saveDuration, int nbSaved, int nbRemainingAfterSave) { + super(0x53, System.currentTimeMillis(), null); + this.saveDuration = saveDuration; + this.nbSaved = nbSaved; + this.nbRemainingAfterSave = nbRemainingAfterSave; + } + + public StatEventAdminSaveLog(DataInputStream is, long serverTime, String ipClient, Map header, + int activeCount, long freeMemory, long totalMemory) throws IOException { + super(0x53, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + this.saveDuration = is.readInt(); + this.nbSaved = is.readInt(); + this.nbRemainingAfterSave = is.readInt(); + } + + @Override + public String toString() { + return super.toString() + " SAVELOG " + saveDuration + " ms, nb=" + nbSaved + " remain=" + nbRemainingAfterSave; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStart.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStart.java new file mode 100644 index 0000000..fc9b212 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStart.java @@ -0,0 +1,51 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +public class StatEventAdminStart extends StatEvent { + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + } + + public StatEventAdminStart() { + super(0x51, System.currentTimeMillis(), null); + } + + public StatEventAdminStart(DataInputStream is, long serverTime, String ipClient, Map header, + int activeCount, long freeMemory, long totalMemory) { + super(0x51, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + } + + @Override + public String toString() { + return super.toString() + " START"; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStop.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStop.java new file mode 100644 index 0000000..8b8e168 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventAdminStop.java @@ -0,0 +1,51 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +public class StatEventAdminStop extends StatEvent { + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + } + + public StatEventAdminStop() { + super(0x52, System.currentTimeMillis(), null); + } + + public StatEventAdminStop(DataInputStream is, long serverTime, String ipClient, Map header, int activeCount, + long freeMemory, long totalMemory) { + super(0x52, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + } + + @Override + public String toString() { + return super.toString() + " STOP"; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIterator.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIterator.java new file mode 100644 index 0000000..108f182 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIterator.java @@ -0,0 +1,44 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +public abstract class StatEventFileIterator implements Closeable, Iterator { + + final public void remove() { + throw new UnsupportedOperationException(); + } + + public static StatEventFileIterator fromFile(File f) throws IOException { + if (f.getName().endsWith(".zip")) { + return new StatEventFileIteratorZip(f); + } + return new StatEventFileIteratorSimple(f); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorSimple.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorSimple.java new file mode 100644 index 0000000..acb120b --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorSimple.java @@ -0,0 +1,78 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.zip.GZIPInputStream; + +class StatEventFileIteratorSimple extends StatEventFileIterator { + + private DataInputStream is; + private StatEvent potentialNext; + + public StatEventFileIteratorSimple(File f) throws IOException { + if (f.getName().endsWith(".gz")) { + this.is = new DataInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(f)))); + } else { + this.is = new DataInputStream(new BufferedInputStream(new FileInputStream(f))); + } + this.potentialNext = StatEvent.read(is); + + } + + public void close() throws IOException { + is.close(); + is = null; + } + + public boolean hasNext() { + return potentialNext != null; + } + + public StatEvent next() { + final StatEvent result = potentialNext; + try { + potentialNext = StatEvent.read(is); + } catch (IOException e) { + e.printStackTrace(); + throw new UnsupportedOperationException(); + } + return result; + } + + public static void main(String[] args) throws IOException { + final File f = new File("C:/eclipse/eclipse/pdata2013_11.pat"); + final StatEventFileIteratorSimple it = new StatEventFileIteratorSimple(f); + while (it.hasNext()) { + final StatEvent ev = it.next(); + System.out.println(ev); + } + it.close(); + + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorZip.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorZip.java new file mode 100644 index 0000000..b2ea697 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventFileIteratorZip.java @@ -0,0 +1,89 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +class StatEventFileIteratorZip extends StatEventFileIterator { + + private StatEvent potentialNext; + private ZipInputStream zip; + private ZipEntry current; + private DataInputStream is; + + public StatEventFileIteratorZip(File f) throws IOException { + this.zip = new ZipInputStream(new BufferedInputStream(new FileInputStream(f))); + current = zip.getNextEntry(); + is = new DataInputStream(zip); + this.potentialNext = StatEvent.read(is); + + } + + public void close() throws IOException { + is.close(); + is = null; + } + + public boolean hasNext() { + return potentialNext != null; + } + + public StatEvent next() { + final StatEvent result = potentialNext; + try { + potentialNext = StatEvent.read(is); + if (potentialNext == null) { + current = zip.getNextEntry(); + if (current != null) { + // is = new DataInputStream(zip); + this.potentialNext = StatEvent.read(is); + } + } + } catch (IOException e) { + e.printStackTrace(); + throw new UnsupportedOperationException(); + } + return result; + } + + public static void main(String[] args) throws IOException { + final File f = new File("G:/log2/pdata2013_11.zip"); + final StatEventFileIteratorZip it = new StatEventFileIteratorZip(f); + int nb = 0; + while (it.hasNext()) { + final StatEvent ev = it.next(); + nb++; + // System.out.println(ev); + } + System.err.println("nb=" + nb); + it.close(); + + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlCreate.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlCreate.java new file mode 100644 index 0000000..ab98da0 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlCreate.java @@ -0,0 +1,71 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +public class StatEventHtmlCreate extends StatEvent { + + private final long date1; + private final String token; + private final String encoded; + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + os.writeLong(date1); + writeStringSecure(os, token); + writeStringSecure(os, encoded); + } + + public StatEventHtmlCreate(DataInputStream is, long serverTime, String ipClient, Map header, + int activeCount, long freeMemory, long totalMemory) throws IOException { + super(0x43, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + this.date1 = is.readLong(); + this.token = is.readUTF(); + this.encoded = is.readUTF(); + } + + public StatEventHtmlCreate(HttpServletRequest request, long date0, long date1, String token, String encoded) { + super(0x43, date0, request); + this.date1 = date1; + this.token = token; + this.encoded = encoded; + } + + @Override + public String toString() { + final long duration = date1 - getStartServerTime(); + return super.toString() + " " + token + " (ht=" + duration + "ms) " + shorten(encoded); + } + + public String getToken() { + return token; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadImage.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadImage.java new file mode 100644 index 0000000..622d3de --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadImage.java @@ -0,0 +1,85 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +public class StatEventHtmlLoadImage extends StatEvent { + + private final long start; + private final long end; + private final int width; + private final int height; + private final String token; + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + os.writeLong(start); + os.writeLong(end); + os.writeInt(width); + os.writeInt(height); + writeStringSecure(os, token); + } + + public StatEventHtmlLoadImage(DataInputStream is, long serverTime, String ipClient, Map header, + int activeCount, long freeMemory, long totalMemory) throws IOException { + super(0x45, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + this.start = is.readLong(); + this.end = is.readLong(); + this.width = is.readInt(); + this.height = is.readInt(); + this.token = is.readUTF(); + } + + public StatEventHtmlLoadImage(HttpServletRequest request, long date0, long start, long end, String token, + int width, int height) { + super(0x45, date0, request); + this.start = start; + this.end = end; + this.width = width; + this.height = height; + this.token = token; + } + + @Override + public String toString() { + final long duration = end - start; + return super.toString() + " " + token + " (im=" + duration + "ms) " + width + "x" + height; + } + + public int getImageLoad() { + final long duration = end - start; + return (int) duration; + } + + public String getToken() { + return token; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadPage.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadPage.java new file mode 100644 index 0000000..4768360 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventHtmlLoadPage.java @@ -0,0 +1,86 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +public class StatEventHtmlLoadPage extends StatEvent { + + private final long start; + private final long end; + private final int width; + private final int height; + private final String token; + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + os.writeLong(start); + os.writeLong(end); + os.writeInt(width); + os.writeInt(height); + writeStringSecure(os, token); + } + + public StatEventHtmlLoadPage(DataInputStream is, long serverTime, String ipClient, Map header, + int activeCount, long freeMemory, long totalMemory) throws IOException { + super(0x44, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + this.start = is.readLong(); + this.end = is.readLong(); + this.width = is.readInt(); + this.height = is.readInt(); + this.token = is.readUTF(); + } + + public StatEventHtmlLoadPage(HttpServletRequest request, long date0, long start, long end, String token, int width, + int height) { + super(0x44, date0, request); + this.start = start; + this.end = end; + this.width = width; + this.height = height; + this.token = token; + + } + + @Override + public String toString() { + final long duration = end - start; + return super.toString() + " " + token + " (pa=" + duration + "ms) " + width + "x" + height; + } + + public int getPageLoad() { + final long duration = end - start; + return (int) duration; + } + + public String getToken() { + return token; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventImageGeneration.java b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventImageGeneration.java new file mode 100644 index 0000000..093a88c --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/StatEventImageGeneration.java @@ -0,0 +1,100 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +public class StatEventImageGeneration extends StatEvent { + + private final long date1; + private final String uri; + private String type = "??"; + + @Override + protected void saveSuppData(DataOutputStream os) throws IOException { + os.writeLong(date1); + writeStringSecure(os, uri); + writeStringSecure(os, type); + } + + public StatEventImageGeneration(int byteHeader, DataInputStream is, long serverTime, String ipClient, + Map header, int activeCount, long freeMemory, long totalMemory) throws IOException { + super(byteHeader, serverTime, ipClient, header, activeCount, freeMemory, totalMemory); + this.date1 = is.readLong(); + this.uri = is.readUTF(); + if (byteHeader == 0x47) { + this.type = is.readUTF(); + } + } + + public StatEventImageGeneration(HttpServletRequest request, long date0, long date1, String type) { + super(0x47, date0, request); + this.date1 = date1; + this.uri = request.getRequestURI(); + this.type = type; + } + + public StatEventImageGeneration(long date0, String uri, String type) { + super(0x47, date0, null); + this.date1 = 0; + this.uri = uri; + this.type = type; + } + + @Override + public String toString() { + // final long duration = date1 == 0 ? -1 : date1 - getStartServerTime(); + return super.toString() + "(" + type + ") [" + getDuration() + "ms] " + shorten(uri); + } + + public int getDuration() { + final long duration = date1 == 0 ? -1 : date1 - getStartServerTime(); + return (int) duration; + } + + public String getUri() { + return uri; + } + + public String getType() { + return type; + } + + public String getIncomming() { + final String refererer = getReferer(); + if (refererer.startsWith("http://www.plantuml.com")) { + return "www.plantuml.com"; + } + if (refererer.startsWith("http://plantuml.com")) { + return "plantuml.com"; + } + return "Other website"; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/event/UAParser.java b/src/main/java/net/sourceforge/plantuml/pstat/event/UAParser.java new file mode 100644 index 0000000..0564047 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/event/UAParser.java @@ -0,0 +1,65 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.event; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import net.sf.uadetector.OperatingSystem; +import net.sf.uadetector.ReadableUserAgent; +import net.sf.uadetector.UserAgentFamily; +import net.sf.uadetector.UserAgentStringParser; +import net.sf.uadetector.service.UADetectorServiceFactory; + +public class UAParser { + + private static final UserAgentStringParser parser = UADetectorServiceFactory.getResourceModuleParser(); + + private static final Map osMap = new ConcurrentHashMap(); + private static final Map browserMap = new ConcurrentHashMap(); + + public String getOperatingSystem(String userAgent) { + String result = osMap.get(userAgent); + if (result == null) { + final ReadableUserAgent agent = parser.parse(userAgent); + final OperatingSystem os = agent.getOperatingSystem(); + result = os.getName(); + osMap.put(userAgent, result); + // System.err.println("os=" + osMap.size()); + } + return result; + } + + public String getBrowser(String userAgent) { + String result = browserMap.get(userAgent); + if (result == null) { + final ReadableUserAgent agent = parser.parse(userAgent); + final UserAgentFamily family = agent.getFamily(); + result = family.getName(); + browserMap.put(userAgent, result); + // System.err.println("browser=" + browserMap.size()); + } + return result; + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/Chart.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/Chart.java new file mode 100644 index 0000000..ddd7aa3 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/Chart.java @@ -0,0 +1,285 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import java.awt.Font; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.pstat.WriterOutputStream; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UEllipse; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UText; +import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.ugraphic.svg.UGraphicSvg; + +public class Chart { + + class Data { + final private String label; + final private int value; + + Data(String label, int value) { + this.label = label; + this.value = value; + } + + private double getAngle() { + return 360.0 * value / sum; + } + + private String getFullLabel() { + final long pour = 100L * value / sum; + return label + " [" + pour + "%] [" + value + "/" + sum + "]"; + } + + public String getLabelShort() { + if (label.length() > 40) { + return "..."; + } + return label; + } + } + + private final List datas = new ArrayList(); + private long sum; + private final UFont fontComment = new UFont("", Font.BOLD, 12); + + public void compact() { + final List newList = new ArrayList(); + final StringBuilder relicat = new StringBuilder(); + int relicatValue = 0; + final int limit = (int) (sum / 100); + for (Data d : datas) { + if (d.value > limit) { + newList.add(d); + } else { + if (relicat.length() > 0) { + relicat.append(" - "); + } + relicat.append(d.label); + relicatValue += d.value; + } + } + if (relicatValue > 0) { + newList.add(new Data(relicat.toString(), relicatValue)); + } + datas.clear(); + datas.addAll(newList); + } + + public void removeBig(double pour) { + final List newList = new ArrayList(); + final int limit = (int) (sum * pour); + for (Data d : datas) { + if (d.value <= limit) { + newList.add(d); + } else { + sum -= d.value; + } + } + datas.clear(); + datas.addAll(newList); + } + + private final double heightGraph; + private final List colors = Arrays.asList(HtmlColorUtils.getColorIfValid("CadetBlue"), + HtmlColorUtils.getColorIfValid("Sienna"), HtmlColorUtils.getColorIfValid("Khaki"), + HtmlColorUtils.getColorIfValid("GreenYellow"), HtmlColorUtils.getColorIfValid("Olive"), + HtmlColorUtils.GRAY, HtmlColorUtils.getColorIfValid("HotPink"), + HtmlColorUtils.getColorIfValid("LightBlue"), HtmlColorUtils.getColorIfValid("Orange"), + HtmlColorUtils.getColorIfValid("OrangeRed"), HtmlColorUtils.getColorIfValid("Chocolate"), + HtmlColorUtils.getColorIfValid("Coral")); + + public Chart(double height) { + this.heightGraph = height; + } + + public void addData(String label, int value) { + datas.add(new Data(label, value)); + this.sum += value; + } + + private void drawPart(UGraphic ug, double v1, double v2, HtmlColor color, String title) { + if (v2 < 180) { + drawPartInternal(ug, v1, v2, color, title); + } else { + drawPartInternal(ug, v1, v2 / 2, color, title); + drawPartInternal(ug, v1 + v2 / 2, v2 / 2, color, title); + } + } + + private void drawPartInternal(UGraphic ug, double v1, double v2, HtmlColor color, String title) { + // System.err.println("v1=" + v1 + " v2=" + v2 + " v1+v2=" + (v1 + v2)); + ug = ug.apply(new UStroke(0)); + ug = ug.apply(new UChangeBackColor(color)).apply(new UChangeColor(color)); + ug.startUrl(new Url("", title)); + ug.apply(new UStroke(2)).draw(new UEllipse(heightGraph, heightGraph, v1, v2)); + + final double cx = heightGraph / 2; + final double cy = heightGraph / 2; + + final double start = v1 + 90; + final double extend = v2; + + final double x1 = cx + Math.sin(start * Math.PI / 180.) * heightGraph / 2; + final double y1 = cy + Math.cos(start * Math.PI / 180.) * heightGraph / 2; + final double x2 = cx + Math.sin((start + extend) * Math.PI / 180.) * heightGraph / 2; + final double y2 = cy + Math.cos((start + extend) * Math.PI / 180.) * heightGraph / 2; + + final UPolygon poly = new UPolygon(); + poly.addPoint(heightGraph / 2, heightGraph / 2); + poly.addPoint(x1, y1); + poly.addPoint(x2, y2); + ug.apply(new UStroke(1.5)).draw(poly); + ug.closeAction(); + + } + + private void drawPartComment(UGraphic ug, double v1, double v2, String title) { + final double cx = heightGraph / 2; + final double cy = heightGraph / 2; + + final double start = v1 + 90; + final double extend = v2; + + final double middle = (start + extend / 2) * Math.PI / 180.; + final double x3 = cx + Math.sin(middle) * (heightGraph / 2 * 4 / 5); + final double y3 = cy + Math.cos(middle) * (heightGraph / 2 * 4 / 5); + final double x4 = cx + Math.sin(middle) * (heightGraph / 2 + 20); + final double y4 = cy + Math.cos(middle) * (heightGraph / 2 + 20); + + ug = ug.apply(new UStroke(2)); + ug = ug.apply(new UChangeColor(HtmlColorUtils.BLACK)); + + drawLine(ug, x3, y3, x4, y4); + + final UText text = new UText(title, new FontConfiguration(fontComment, HtmlColorUtils.BLACK)); + final double textWidth = ug.getStringBounder().calculateDimension(fontComment, title).getWidth(); + final double xText; + if (x4 < cx) { + xText = x4 - textWidth - 3; + } else { + xText = x4 + 3; + } + ug.apply(new UTranslate(xText, y4)).draw(text); + + } + + private void drawPartLimit(UGraphic ug, double v1, double v2) { + ug = ug.apply(new UStroke(1.5)); + + final double cx = heightGraph / 2; + final double cy = heightGraph / 2; + + final double start = v1 + 90; + final double extend = v2; + + final double x1 = cx + Math.sin(start * Math.PI / 180.) * heightGraph / 2; + final double y1 = cy + Math.cos(start * Math.PI / 180.) * heightGraph / 2; + + drawLine(ug, cx, cy, x1, y1); + + } + + private void drawLine(UGraphic ug, double x1, double y1, double x2, double y2) { + ug = ug.apply(new UTranslate(x1, y1)); + ug.draw(new ULine(x2 - x1, y2 - y1)); + } + + private double getMaxTitleWidth(StringBounder stringBounder) { + double result = 0; + for (Data data : datas) { + if (data.value == 0) { + continue; + } + final double textWidth = stringBounder.calculateDimension(fontComment, data.getLabelShort()).getWidth(); + result = Math.max(result, textWidth); + } + return result * 1.1 + 20; + } + + public void printSvg(Writer writer) throws IOException { + + UGraphic ug = new UGraphicSvg(new ColorMapperIdentity(), false, 1.0); + double wmargin = getMaxTitleWidth(ug.getStringBounder()); + ug = ug.apply(new UTranslate(wmargin, 40)); + ug = ug.apply(new UChangeColor(HtmlColorUtils.WHITE)); + ug = ug.apply(new UChangeBackColor(HtmlColorUtils.WHITE)); + ug.apply(new UTranslate(heightGraph + wmargin, 0)).draw(new URectangle(1, 1)); + ug = ug.apply(new UChangeColor(HtmlColorUtils.BLACK)); + ug = ug.apply(new UChangeBackColor(HtmlColorUtils.BLUE)); + + double s = 0; + ug = ug.apply(new UChangeBackColor(HtmlColorUtils.GREEN)); + Iterator cols = colors.iterator(); + for (Data data : datas) { + if (data.value == 0) { + continue; + } + if (cols.hasNext() == false) { + cols = colors.iterator(); + } + drawPart(ug, s, data.getAngle(), cols.next(), data.getFullLabel()); + s += data.getAngle(); + } + s = 0; + for (Data data : datas) { + if (data.value == 0) { + continue; + } + drawPartLimit(ug, s, data.getAngle()); + drawPartComment(ug, s, data.getAngle(), data.getLabelShort()); + s += data.getAngle(); + } + ug = ug.apply(new UStroke(2)); + ug = ug.apply(new UChangeColor(HtmlColorUtils.BLACK)); + ug = ug.apply(new UChangeBackColor(null)); + ug.draw(new UEllipse(heightGraph, heightGraph)); + + OutputStream os = new WriterOutputStream(writer); + ug.writeImage(os, null, 96); + os.flush(); + + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/ChartProducer.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/ChartProducer.java new file mode 100644 index 0000000..3ae09f5 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/ChartProducer.java @@ -0,0 +1,135 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ChartProducer { + + private final Collection datas; + + public ChartProducer(Collection all) { + datas = all; + } + + public Chart getChart(double height) { + final Chart chart = new Chart(height); + final int nb = datas.size(); + if (nb == 0) { + return chart; + } + + long sum = 0; + int max = 0; + for (int v : datas) { + sum += v; + max = Math.max(max, v); + } + + final int mean = NiceNumber.getNicer((int) (sum / nb)); + + final List steps = new ArrayList(); + steps.add(new Step(0, NiceNumber.getNicer(mean / 3))); + steps.add(new Step(NiceNumber.getNicer(mean / 3), NiceNumber.getNicer(2 * mean / 3))); + steps.add(new Step(NiceNumber.getNicer(2 * mean / 3), mean)); + final int delta = (max - mean) / 3; + steps.add(new Step(mean, NiceNumber.getNicer(mean + delta))); + steps.add(new Step(NiceNumber.getNicer(mean + delta), NiceNumber.getNicer(mean + 2 * delta))); + steps.add(new Step(NiceNumber.getNicer(mean + 2 * delta), max + 1)); + + for (int v : datas) { + count(steps, v); + } + final int lim = datas.size() / 50; + while (eventuallyMerge(steps, lim)) { + + } + + for (Step s : steps) { + chart.addData(s.getTitle(), s.count); + } + return chart; + } + + static class Step { + final private int from; + final private int to; + private int count; + + Step(int from, int to) { + this.from = from; + this.to = to; + } + + Step mergeWith(Step other) { + if (this.to != other.from) { + throw new IllegalArgumentException(); + } + final Step result = new Step(this.from, other.to); + result.count = this.count + other.count; + return result; + } + + @Override + public String toString() { + return "" + from + "->" + to + " (" + count + ")"; + } + + boolean count(int v) { + if (v >= from && v < to) { + count++; + return true; + } + return false; + } + + String getTitle() { + return "" + from + " ms to " + to + " ms"; + } + } + + private void count(final List steps, int v) { + for (Step s : steps) { + if (s.count(v)) { + return; + } + } + } + + private boolean eventuallyMerge(final List steps, final int lim) { + for (int i = 0; i < steps.size() - 1; i++) { + final Step s1 = steps.get(i); + final Step s2 = steps.get(i + 1); + if (s1.count < lim && s2.count < lim) { + steps.set(i, s1.mergeWith(s2)); + steps.remove(i + 1); + return true; + } + } + return false; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/Curve.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/Curve.java new file mode 100644 index 0000000..ce361bc --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/Curve.java @@ -0,0 +1,156 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import java.awt.Font; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.pstat.WriterOutputStream; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UEllipse; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UText; +import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.ugraphic.svg.UGraphicSvg; + +public class Curve { + + static class Data { + final String label; + final int[] value; + + Data(String label, int[] value) { + this.label = label; + this.value = value; + } + } + + private final HtmlColor backColor = HtmlColorUtils.getColorIfValid("#AFE0D0"); + // private final HtmlColor lineColor = HtmlColorUtils.getColorIfValid("DimGray"); + private final UFont fontLegend; + private final List datas = new ArrayList(); + private int max; + private final double heightGraph; + private final double singleBarWidth; + + public Curve(double height, double singleBarWidth, int fontSize) { + this.heightGraph = height; + this.singleBarWidth = singleBarWidth; + this.fontLegend = new UFont("", Font.BOLD, fontSize); + } + + public void addData(String label, int... value) { + datas.add(new Data(label, value)); + for (Data data : datas) { + for (int v : data.value) { + max = Math.max(max, v); + } + } + } + + public void printSvg(Writer writer) throws IOException { + UGraphic ug = new UGraphicSvg(new ColorMapperIdentity(), false, 1.0); + ug = ug.apply(new UChangeColor(backColor)); + ug = ug.apply(new UChangeBackColor(backColor)); + + final double coef = heightGraph / max; + + int step = getRound(max / 10.0); + if (step == 0) { + step = 1; + } + final double margeY1 = 10; + + traceInfo(ug, coef, margeY1); + printScale(ug.apply(new UTranslate(0, heightGraph + margeY1)), step, coef, datas.size() * singleBarWidth + 30); + + for (int i = 0; i < datas.get(0).value.length; i++) { + traceCurve(ug, coef, margeY1, i); + } + + OutputStream os = new WriterOutputStream(writer); + ug.writeImage(os, null, 96); + os.flush(); + + } + + private void traceInfo(UGraphic ug, final double coef, final double margeY1) { + ug = ug.apply(new UTranslate(20, heightGraph + margeY1)); + ug = ug.apply(new UChangeColor(HtmlColorUtils.WHITE)).apply(new UChangeBackColor(HtmlColorUtils.WHITE)); + for (Data data : datas) { + ug.startUrl(new Url("", data.label)); + ug.apply(new UTranslate(-3, -heightGraph - margeY1)).draw( + new URectangle(singleBarWidth, heightGraph + margeY1)); + ug.closeAction(); + ug = ug.apply(new UTranslate(singleBarWidth, 0)); + } + } + + private void traceCurve(UGraphic ug, final double coef, final double margeY1, int i) { + ug = ug.apply(new UTranslate(20, heightGraph + margeY1)); + Data lastData = null; + for (Data data : datas) { + ug.apply(new UTranslate(-3, -(data.value[i] * coef) - 3)).draw(new UEllipse(5, 5)); + if (lastData != null) { + final ULine line = new ULine(-singleBarWidth, (data.value[i] - lastData.value[i]) * coef); + ug.apply(new UTranslate(0, -(data.value[i] * coef))).apply(new UStroke(2)).draw(line); + } + ug = ug.apply(new UTranslate(singleBarWidth, 0)); + lastData = data; + } + } + + private int getRound(double value) { + final int step = (int) Math.ceil(value / 5.0); + return step * 5; + } + + private void printScale(UGraphic ug, int step, double coef, double totalWidth) { + final FontConfiguration fontConfiguration = new FontConfiguration(fontLegend, HtmlColorUtils.BLACK); + final ULine hline = new ULine(totalWidth, 0); + ug = ug.apply(new UChangeColor(HtmlColorUtils.GRAY)); + for (int i = 0; i <= max; i += step) { + final double v = i * coef; + String label = "" + i; + final UText text = new UText(label, fontConfiguration); + ug.apply(new UTranslate(0, -v)).draw(text); + ug.apply(new UTranslate(10, -v)).apply(new UStroke(2, 2, 1)).draw(hline); + } + + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/HistoList.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/HistoList.java new file mode 100644 index 0000000..67d2071 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/HistoList.java @@ -0,0 +1,174 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import java.awt.Font; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.pstat.WriterOutputStream; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UText; +import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.ugraphic.svg.UGraphicSvg; + +public class HistoList { + + static class Data implements Comparable { + final String label; + final int value; + + Data(String label, int value) { + this.label = label; + this.value = value; + } + + public int compareTo(Data other) { + return other.value - this.value; + } + } + + private final HtmlColor backColor = HtmlColorUtils.getColorIfValid("#AFE0D0"); + // private final HtmlColor lineColor = HtmlColorUtils.getColorIfValid("DimGray"); + private final UFont fontLegend; + private final List datas = new ArrayList(); + private final double graphWidth; + private int max = 1; + private long sum; + private final double singleBarHeight; + + public HistoList(double graphWidth, double singleBarHeight, int fontSize) { + this.graphWidth = graphWidth; + this.singleBarHeight = singleBarHeight; + this.fontLegend = new UFont("", Font.BOLD, fontSize); + } + + public void addData(String label, int value) { + datas.add(new Data(label, value)); + max = Math.max(max, value); + sum += value; + } + + public void printSvg(Writer writer) throws IOException { + UGraphic ug = new UGraphicSvg(new ColorMapperIdentity(), false, 1.0); + // ug = ug.apply(new UTranslate(0, 20)); + + ug = ug.apply(new UChangeColor(backColor)); + ug = ug.apply(new UChangeBackColor(backColor)); + + Collections.sort(datas); + final double coef = graphWidth / max; + + final FontConfiguration fontConfiguration = new FontConfiguration(fontLegend, HtmlColorUtils.BLACK); + for (Data data : datas) { + final long pour = data.value * 100L / sum; + final String title = "[" + pour + "%] [" + data.value + "/" + sum + "]"; + + ug.startUrl(new Url("", title)); + ug.draw(new URectangle(data.value * coef, singleBarHeight - 4)); + ug.closeAction(); + ug.apply(new UTranslate(0, fontLegend.getSize())).draw(new UText(data.label, fontConfiguration)); + ug = ug.apply(new UTranslate(0, singleBarHeight)); + + } + + // final double coef = heightGraph / maxValue(); + + // int step = getRound(maxValue() / 10.0); + // if (step == 0) { + // step = 1; + // } + // final double margeY1 = 10; + // + // traceInfo(ug, coef, margeY1); + // printScale(ug.apply(new UTranslate(0, heightGraph + margeY1)), step, coef, datas.size() * singleBarWidth + + // 30); + // + // for (int i = 0; i < datas.get(0).value.length; i++) { + // traceCurve(ug, coef, margeY1, i); + // } + + OutputStream os = new WriterOutputStream(writer); + ug.writeImage(os, null, 96); + os.flush(); + + } + // private void traceInfo(UGraphic ug, final double coef, final double margeY1) { + // ug = ug.apply(new UTranslate(20, heightGraph + margeY1)); + // ug = ug.apply(new UChangeColor(HtmlColorUtils.WHITE)).apply(new UChangeBackColor(HtmlColorUtils.WHITE)); + // for (Data data : datas) { + // ug.startUrl(new Url("", data.label)); + // ug.apply(new UTranslate(-3, -heightGraph - margeY1)).draw( + // new URectangle(singleBarWidth, heightGraph + margeY1)); + // ug.closeAction(); + // ug = ug.apply(new UTranslate(singleBarWidth, 0)); + // } + // } + + // private void traceCurve(UGraphic ug, final double coef, final double margeY1, int i) { + // ug = ug.apply(new UTranslate(20, heightGraph + margeY1)); + // Data lastData = null; + // for (Data data : datas) { + // ug.apply(new UTranslate(-3, -(data.value[i] * coef) - 3)).draw(new UEllipse(5, 5)); + // if (lastData != null) { + // final ULine line = new ULine(-singleBarWidth, (data.value[i] - lastData.value[i]) * coef); + // ug.apply(new UTranslate(0, -(data.value[i] * coef))).apply(new UStroke(2)).draw(line); + // } + // ug = ug.apply(new UTranslate(singleBarWidth, 0)); + // lastData = data; + // } + // } + // + // private int getRound(double value) { + // final int step = (int) Math.ceil(value / 5.0); + // return step * 5; + // } + + // private void printScale(UGraphic ug, int step, double coef, double totalWidth) { + // final FontConfiguration fontConfiguration = new FontConfiguration(fontLegend, HtmlColorUtils.BLACK); + // final ULine hline = new ULine(totalWidth, 0); + // ug = ug.apply(new UChangeColor(HtmlColorUtils.GRAY)); + // for (int i = 0; i <= maxValue(); i += step) { + // final double v = i * coef; + // String label = "" + i; + // final UText text = new UText(label, fontConfiguration); + // ug.apply(new UTranslate(0, -v)).draw(text); + // ug.apply(new UTranslate(10, -v)).apply(new UStroke(2, 2, 1)).draw(hline); + // } + // + // } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/Histogram.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/Histogram.java new file mode 100644 index 0000000..b33ac8c --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/Histogram.java @@ -0,0 +1,153 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import java.awt.Font; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.pstat.WriterOutputStream; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UText; +import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.ugraphic.svg.UGraphicSvg; + +public class Histogram { + + static class Data { + final String label; + final String title; + final int value; + + Data(String label, String title, int value) { + this.label = label; + this.title = title; + this.value = value; + } + } + + private final HtmlColor backColor = HtmlColorUtils.getColorIfValid("#AFE0D0"); + private final HtmlColor lineColor = HtmlColorUtils.getColorIfValid("DimGray"); + private final UFont fontLegend; + private final List datas = new ArrayList(); + private int max = 1; + private final double heightGraph; + private final double singleBarWidth; + + public Histogram(double height, double singleBarWidth, int fontSize) { + this.heightGraph = height; + this.singleBarWidth = singleBarWidth; + this.fontLegend = new UFont("", Font.BOLD, fontSize); + } + + public void addData(String label, int value, String title) { + datas.add(new Data(label, title, value)); + max = Math.max(max, value); + } + + public void printSvg(Writer writer) throws IOException { + UGraphic ug = new UGraphicSvg(new ColorMapperIdentity(), false, 1.0); + ug = ug.apply(new UChangeColor(null)); + ug = ug.apply(new UChangeBackColor(backColor)); + + final double coef = heightGraph / max; + + int step = getRound(max / 10.0); + if (step == 0) { + step = 1; + } + final double margeY1 = 10; + printScale(ug.apply(new UTranslate(0, heightGraph + margeY1)), step, coef, datas.size() * singleBarWidth + 30); + + final int marginX = 8 + ("" + max).length() * 8; + UGraphic ug2 = ug.apply(new UTranslate(marginX, heightGraph + margeY1)); + final FontConfiguration fontConfiguration = new FontConfiguration(fontLegend, HtmlColorUtils.BLACK); + for (Data data : datas) { + final double v = data.value * coef; + ug2.startUrl(new Url("", data.title)); + ug2.apply(new UTranslate(0, -v)).draw(new URectangle(singleBarWidth, v)); + ug2.closeAction(); + final double textHeight = ug.getStringBounder().calculateDimension(fontLegend, data.label).getHeight(); + final double textWidth = ug.getStringBounder().calculateDimension(fontLegend, data.label).getWidth(); + final double xtext = (singleBarWidth - textWidth) / 2; + ug2.apply(new UTranslate(xtext, textHeight - 2)).draw(new UText(data.label, fontConfiguration)); + ug2 = ug2.apply(new UTranslate(singleBarWidth, 0)); + } + + ug = ug.apply(new UChangeColor(lineColor)).apply(new UStroke(2)).apply(new UChangeBackColor(null)); + ug2 = ug.apply(new UTranslate(marginX, heightGraph + margeY1)); + double lastV = 0; + for (Data data : datas) { + final double v = data.value * coef; + drawLine(ug2, 0, -lastV, 0, -v); + drawLine(ug2, 0, -v, singleBarWidth, -v); + lastV = v; + ug2 = ug2.apply(new UTranslate(singleBarWidth, 0)); + } + drawLine(ug2, 0, -lastV, 0, 0); + + OutputStream os = new WriterOutputStream(writer); + ug.writeImage(os, null, 96); + os.flush(); + + } + + private void drawLine(UGraphic ug, double x1, double y1, double x2, double y2) { + ug = ug.apply(new UTranslate(x1, y1)); + ug.draw(new ULine(x2 - x1, y2 - y1)); + } + + private int getRound(double value) { + final int step = (int) Math.ceil(value / 5.0); + return NiceNumber.getNicer(step * 5); + } + + private void printScale(UGraphic ug, int step, double coef, double totalWidth) { + final FontConfiguration fontConfiguration = new FontConfiguration(fontLegend, HtmlColorUtils.BLACK); + final ULine hline = new ULine(totalWidth, 0); + ug = ug.apply(new UChangeColor(HtmlColorUtils.GRAY)); + for (int i = 0; i <= max; i += step) { + final double v = i * coef; + String label = "" + i; + final UText text = new UText(label, fontConfiguration); + ug.apply(new UTranslate(0, -v)).draw(text); + ug.apply(new UTranslate(10, -v)).apply(new UStroke(2, 2, 1)).draw(hline); + } + + } +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/HistogramBuilder.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/HistogramBuilder.java new file mode 100644 index 0000000..094d21a --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/HistogramBuilder.java @@ -0,0 +1,66 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import java.util.TreeMap; + +import net.sourceforge.plantuml.pstat.time.DateManager; + +public class HistogramBuilder { + + private final DateManager dateManager; + private final int histoSize; + private final TreeMap data = new TreeMap(); + + public HistogramBuilder(DateManager dateManager, int histoSize) { + this.dateManager = dateManager; + this.histoSize = histoSize; + } + + public Histogram getHistogram(double height, double singleBarWidth, int fontSize) { + final Histogram histogram = new Histogram(height, singleBarWidth, fontSize); + if (data.size() > 0) { + final int last = data.lastKey(); + for (int i = last - histoSize + 1; i <= last; i++) { + final String label = dateManager.getDescriptionShort(i); + final MutableInteger n = data.get(i); + final int value = n == null ? 0 : n.intValue(); + final String title = "[" + value + " diagrams] at [" + dateManager.getDescription(i) + "]"; + histogram.addData(label, value, title); + } + } + return histogram; + } + + public void incKey(long time, int value) { + final int k = dateManager.toNumber(time); + final MutableInteger v = data.get(k); + if (v == null) { + data.put(k, new MutableInteger(value)); + } else { + v.inc(value); + } + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/MutableInteger.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/MutableInteger.java new file mode 100644 index 0000000..01c4722 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/MutableInteger.java @@ -0,0 +1,42 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +public class MutableInteger { + + private int value; + + public MutableInteger(int value) { + this.value = value; + } + + public void inc(int delta) { + value += delta; + } + + public int intValue() { + return value; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumber.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumber.java new file mode 100644 index 0000000..23a4fae --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumber.java @@ -0,0 +1,47 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +public class NiceNumber { + + public static int getNicer(final int value) { + if (value <= 18) { + return value; + } + if (value < 93) { + return ((value + 2) / 5) * 5; + } + if (value < 100) { + return ((value + 5) / 10) * 10; + } + int m = 1; + double head = value; + while (head >= 100) { + head = head / 10.0; + m *= 10; + } + return getNicer((int) Math.round(head)) * m; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumberTest.java b/src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumberTest.java new file mode 100644 index 0000000..d2feaf3 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/graph/NiceNumberTest.java @@ -0,0 +1,95 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.graph; + +import junit.framework.TestCase; + +public class NiceNumberTest extends TestCase { + + public void testGetNicer203() { + assertEquals(200, NiceNumber.getNicer(203)); + assertEquals(1200, NiceNumber.getNicer(1154)); + } + + public void testGetNicer5249() { + assertEquals(5000, NiceNumber.getNicer(5249)); + assertEquals(5500, NiceNumber.getNicer(5250)); + } + + public void testGetNicerFull() { + assertEquals(-1, NiceNumber.getNicer(-1)); + assertEquals(1, NiceNumber.getNicer(1)); + assertEquals(2, NiceNumber.getNicer(2)); + assertEquals(3, NiceNumber.getNicer(3)); + assertEquals(4, NiceNumber.getNicer(4)); + assertEquals(5, NiceNumber.getNicer(5)); + assertEquals(6, NiceNumber.getNicer(6)); + assertEquals(7, NiceNumber.getNicer(7)); + assertEquals(8, NiceNumber.getNicer(8)); + assertEquals(9, NiceNumber.getNicer(9)); + assertEquals(10, NiceNumber.getNicer(10)); + assertEquals(11, NiceNumber.getNicer(11)); + assertEquals(12, NiceNumber.getNicer(12)); + assertEquals(13, NiceNumber.getNicer(13)); + assertEquals(14, NiceNumber.getNicer(14)); + assertEquals(15, NiceNumber.getNicer(15)); + assertEquals(16, NiceNumber.getNicer(16)); + assertEquals(17, NiceNumber.getNicer(17)); + assertEquals(18, NiceNumber.getNicer(18)); + assertEquals(20, NiceNumber.getNicer(19)); + assertEquals(20, NiceNumber.getNicer(20)); + assertEquals(20, NiceNumber.getNicer(21)); + assertEquals(20, NiceNumber.getNicer(22)); + assertEquals(25, NiceNumber.getNicer(23)); + assertEquals(25, NiceNumber.getNicer(24)); + assertEquals(25, NiceNumber.getNicer(25)); + assertEquals(25, NiceNumber.getNicer(26)); + assertEquals(25, NiceNumber.getNicer(27)); + assertEquals(30, NiceNumber.getNicer(28)); + assertEquals(30, NiceNumber.getNicer(29)); + assertEquals(30, NiceNumber.getNicer(30)); + assertEquals(80, NiceNumber.getNicer(80)); + assertEquals(80, NiceNumber.getNicer(81)); + assertEquals(80, NiceNumber.getNicer(82)); + assertEquals(85, NiceNumber.getNicer(83)); + assertEquals(85, NiceNumber.getNicer(84)); + assertEquals(85, NiceNumber.getNicer(85)); + assertEquals(85, NiceNumber.getNicer(86)); + assertEquals(85, NiceNumber.getNicer(87)); + assertEquals(90, NiceNumber.getNicer(88)); + assertEquals(90, NiceNumber.getNicer(89)); + assertEquals(90, NiceNumber.getNicer(90)); + assertEquals(90, NiceNumber.getNicer(91)); + assertEquals(90, NiceNumber.getNicer(92)); + assertEquals(90, NiceNumber.getNicer(93)); + assertEquals(90, NiceNumber.getNicer(94)); + assertEquals(100, NiceNumber.getNicer(95)); + assertEquals(100, NiceNumber.getNicer(96)); + assertEquals(100, NiceNumber.getNicer(97)); + assertEquals(100, NiceNumber.getNicer(98)); + assertEquals(100, NiceNumber.getNicer(99)); + + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetInteger.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetInteger.java new file mode 100644 index 0000000..ad50bd0 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetInteger.java @@ -0,0 +1,56 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.pstat.graph.Chart; +import net.sourceforge.plantuml.pstat.graph.ChartProducer; +import net.sourceforge.plantuml.pstat.graph.HistogramBuilder; +import net.sourceforge.plantuml.pstat.time.DateManager; + +public class CounterSetInteger { + + private final List imageGeneration = new ArrayList(); + private final HistogramBuilder builder; + + public HistogramBuilder getHistogramBuilder() { + return builder; + } + + public Chart getChartImageGeneration(double height) { + return new ChartProducer(imageGeneration).getChart(height); + } + + public CounterSetInteger(DateManager dateManager, int histoSize) { + builder = new HistogramBuilder(dateManager, histoSize); + } + + public void increment(TickImageGeneration tick) { + imageGeneration.add(tick.getDuration()); + builder.incKey(tick.getStartMinute() * 1000L * 60, 1); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetLoad.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetLoad.java new file mode 100644 index 0000000..948bdf2 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetLoad.java @@ -0,0 +1,57 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.ArrayList; +import java.util.Collection; + +import net.sourceforge.plantuml.pstat.graph.Chart; +import net.sourceforge.plantuml.pstat.graph.ChartProducer; + +public class CounterSetLoad { + + private final Collection pageLoad = new ArrayList(); + private final Collection imageLoad = new ArrayList(); + + public CounterSetLoad() { + } + + public void increment(TickBrowser tick) { + if (tick.getImageLoad() > 0) { + imageLoad.add(tick.getImageLoad()); + } + if (tick.getPageLoad() > 0) { + pageLoad.add(tick.getPageLoad()); + } + } + + public Chart getChartPageLoad(double height) { + return new ChartProducer(pageLoad).getChart(height); + } + + public Chart getChartImageLoad(double height) { + return new ChartProducer(imageLoad).getChart(height); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetString.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetString.java new file mode 100644 index 0000000..afc23c1 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/CounterSetString.java @@ -0,0 +1,146 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.Map; +import java.util.TreeMap; + +import net.sourceforge.plantuml.pstat.graph.Chart; +import net.sourceforge.plantuml.pstat.graph.HistoList; + +public class CounterSetString { + + private final Map language = new TreeMap(); + private final Map host = new TreeMap(); + private final Map operationSystem = new TreeMap(); + private final Map browser = new TreeMap(); + private final Map referer = new TreeMap(); + private final Map type = new TreeMap(); + private final Map incomming = new TreeMap(); + private final Map country = new TreeMap(); + + public void increment(TickImageGeneration tick) { + increment(language, tick.getAcceptLanguage()); + increment(host, tick.getHost()); + increment(operationSystem, tick.getOperatingSystem()); + increment(browser, tick.getBrowser()); + increment(referer, tick.getReferer()); + increment(type, tick.getType()); + increment(incomming, tick.getIncomming()); + increment(country, tick.getCountry()); + } + + private void increment(Map data, String s) { + final Integer v = data.get(s); + if (v == null) { + data.put(s, 1); + } else { + data.put(s, v + 1); + } + } + + public String getTitle() { + return "language.getTitle()"; + } + + public Chart getChartLanguage(double height) { + return getChart(height, language); + } + + public Chart getChartHost(double height) { + return getChart(height, host); + } + + public Chart getChartOperationSystem(double height) { + return getChart(height, operationSystem); + } + + public Chart getChartBrowser(double height) { + return getChart(height, browser); + } + + public Chart getChartReferer(double height) { + return getChart(height, referer); + } + + public Chart getChartType(double height) { + return getChart(height, type); + } + + public Chart getChartIncomming(double height) { + return getChart(height, incomming); + } + + private Chart getChart(double height, Map counter) { + final Chart chart = new Chart(height); + for (Map.Entry ent : counter.entrySet()) { + final String s = ent.getKey(); + if ("??".equals(s)) { + continue; + } + chart.addData(s, ent.getValue()); + } + chart.compact(); + return chart; + } + + public Chart getChartRefererOther(double height) { + final Chart chart = new Chart(height); + for (Map.Entry ent : referer.entrySet()) { + final String s = ent.getKey(); + if ("??".equals(s) || "http://www.plantuml.com".equals(s) || "http://plantuml.com".equals(s) + || "http://plantuml.sourceforge.net".equals(s) || "Other".equals(s)) { + continue; + } + chart.addData(s, ent.getValue()); + } + chart.removeBig(0.5); + return chart; + } + + public HistoList getHistoListReferer(double graphWidth, double singleBarHeight, int fontSize) { + final HistoList chart = new HistoList(graphWidth, singleBarHeight, fontSize); + for (Map.Entry ent : referer.entrySet()) { + final String s = ent.getKey(); + if ("??".equals(s)) { + continue; + } + chart.addData(s, ent.getValue()); + } + return chart; + } + + public HistoList getHistoListCountry(double graphWidth, double singleBarHeight, int fontSize) { + final HistoList chart = new HistoList(graphWidth, singleBarHeight, fontSize); + for (Map.Entry ent : country.entrySet()) { + final String s = ent.getKey(); + if ("??".equals(s)) { + continue; + } + chart.addData(s, ent.getValue()); + } + return chart; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/DailyStat.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/DailyStat.java new file mode 100644 index 0000000..2b06ea1 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/DailyStat.java @@ -0,0 +1,42 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.concurrent.atomic.AtomicInteger; + +import net.sourceforge.plantuml.pstat.event.StatEventImageGeneration; + +public class DailyStat { + + private final AtomicInteger size = new AtomicInteger(); + + public void updateStats(StatEventImageGeneration ev) { + size.incrementAndGet(); + } + + public int getSize() { + return size.intValue(); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/Day.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/Day.java new file mode 100644 index 0000000..ec516c6 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/Day.java @@ -0,0 +1,56 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.Date; + +public class Day { + + private final int nday; + + public Day(long time) { + nday = (int) (time / 1000L / 3600 / 24); + } + + @Override + public int hashCode() { + return nday; + } + + @Override + public boolean equals(Object o) { + final Day other = (Day) o; + return nday == other.nday; + } + + @Override + public String toString() { + return new Date(nday * 1000L * 3600 * 24).toGMTString(); + } + + public long getTime() { + return nday * 1000L * 3600 * 24; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/GraphData.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/GraphData.java new file mode 100644 index 0000000..efc29d6 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/GraphData.java @@ -0,0 +1,152 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.Iterator; + +import net.sourceforge.plantuml.pstat.time.DateManager; + +public class GraphData { + + // private final CounterSet2 days31 = new CounterSet2(); + private final CounterSetString days15 = new CounterSetString(); + private final CounterSetString hours48 = new CounterSetString(); + private final CounterSetString minutes60 = new CounterSetString(); + private final CounterSetString minutes10 = new CounterSetString(); + + private final CounterSetInteger hdays15 = new CounterSetInteger(DateManager.DAILY, 15); + private final CounterSetInteger hhours48 = new CounterSetInteger(DateManager.HOURLY, 48); + private final CounterSetInteger hminutes60 = new CounterSetInteger(DateManager.MINUTELY, 60); + private final CounterSetInteger hminutes10 = new CounterSetInteger(DateManager.MINUTELY, 10); + + private final CounterSetLoad browserDay15 = new CounterSetLoad(); + private final CounterSetLoad browserHours48 = new CounterSetLoad(); + private final CounterSetLoad browserMinutes60 = new CounterSetLoad(); + private final CounterSetLoad browserMinutes10 = new CounterSetLoad(); + + public GraphData() { + } + + public GraphData(Iterator iterator, Iterator iterator2) { + final int now = (int) (System.currentTimeMillis() / 1000L / 60); + while (iterator.hasNext()) { + final TickImageGeneration tick = iterator.next(); + final int startMinute = tick.getStartMinute(); + // if (startMinute >= now - 31 * 24 * 50) { + // days31.increment(tick); + // } else { + // iterator.remove(); + // } + if (startMinute >= now - 15 * 24 * 60) { + days15.increment(tick); + hdays15.increment(tick); + } else { + iterator.remove(); + } + if (startMinute >= now - 48 * 60) { + hours48.increment(tick); + hhours48.increment(tick); + } + if (startMinute >= now - 60) { + minutes60.increment(tick); + hminutes60.increment(tick); + } + if (startMinute >= now - 10) { + minutes10.increment(tick); + hminutes10.increment(tick); + } + } + while (iterator2.hasNext()) { + final TickBrowser tick = iterator2.next(); + final int startMinute = tick.getStartMinute(); + if (startMinute >= now - 15 * 24 * 60) { + browserDay15.increment(tick); + } else { + iterator2.remove(); + } + if (startMinute >= now - 24 * 60) { + browserHours48.increment(tick); + } + if (startMinute >= now - 60) { + browserMinutes60.increment(tick); + } + if (startMinute >= now - 10) { + browserMinutes10.increment(tick); + } + } + } + + // public final CounterSet2 days31() { + // return days31; + // } + + public final CounterSetString days15() { + return days15; + } + + public final CounterSetString hours48() { + return hours48; + } + + public final CounterSetString minutes60() { + return minutes60; + } + + public final CounterSetString minutes10() { + return minutes10; + } + + public final CounterSetInteger hdays15() { + return hdays15; + } + + public final CounterSetInteger hhours48() { + return hhours48; + } + + public final CounterSetInteger hminutes60() { + return hminutes60; + } + + public final CounterSetInteger hminutes10() { + return hminutes10; + } + + public final CounterSetLoad bdays15() { + return browserDay15; + } + + public final CounterSetLoad bhours48() { + return browserHours48; + } + + public final CounterSetLoad bminutes60() { + return browserMinutes60; + } + + public final CounterSetLoad bminutes10() { + return browserMinutes10; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/GraphDataLongTerm.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/GraphDataLongTerm.java new file mode 100644 index 0000000..3289ec0 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/GraphDataLongTerm.java @@ -0,0 +1,53 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import net.sourceforge.plantuml.pstat.graph.HistogramBuilder; +import net.sourceforge.plantuml.pstat.time.DateManager; + +public class GraphDataLongTerm { + + private final HistogramBuilder builder = new HistogramBuilder(DateManager.MONTHLY, 24); + + public GraphDataLongTerm(Iterator> it) { + while (it.hasNext()) { + Map.Entry ent = it.next(); + final Day day = ent.getKey(); + final DailyStat stat = ent.getValue(); + builder.incKey(day.getTime(), stat.getSize()); + } + } + + public GraphDataLongTerm() { + } + + public HistogramBuilder getHistogramBuilder() { + return builder; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/TickBrowser.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickBrowser.java new file mode 100644 index 0000000..82404e6 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickBrowser.java @@ -0,0 +1,87 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import net.sourceforge.plantuml.pstat.event.StatEvent; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlCreate; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlLoadImage; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlLoadPage; + +public class TickBrowser { + + // private final String token; + private int pageLoad = -1; + private int imageLoad = -1; + private final int startMinute; + + public TickBrowser(StatEvent stat) { + startMinute = (int) (stat.getStartServerTime() / 1000L / 60); +// if (stat instanceof StatEventHtmlLoadImage) { +// final StatEventHtmlLoadImage ev = (StatEventHtmlLoadImage) stat; +// // token = ev.getToken(); +// +// } else if (stat instanceof StatEventHtmlLoadPage) { +// final StatEventHtmlLoadPage ev = (StatEventHtmlLoadPage) stat; +// // token = ev.getToken(); +// +// } else if (stat instanceof StatEventHtmlCreate) { +// final StatEventHtmlCreate ev = (StatEventHtmlCreate) stat; +// // token = ev.getToken(); +// } else { +// throw new IllegalArgumentException(); +// } + update(stat); + + } + + public void update(StatEvent stat) { + if (stat instanceof StatEventHtmlLoadImage) { + final StatEventHtmlLoadImage ev = (StatEventHtmlLoadImage) stat; + imageLoad = ev.getImageLoad(); + + } else if (stat instanceof StatEventHtmlLoadPage) { + final StatEventHtmlLoadPage ev = (StatEventHtmlLoadPage) stat; + pageLoad = ev.getPageLoad(); + + } else if (stat instanceof StatEventHtmlCreate) { + final StatEventHtmlCreate ev = (StatEventHtmlCreate) stat; + } else { + throw new IllegalArgumentException(); + } + + } + + public final int getPageLoad() { + return pageLoad; + } + + public final int getImageLoad() { + return imageLoad; + } + + public final int getStartMinute() { + return startMinute; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/TickCollectionFilterTime.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickCollectionFilterTime.java new file mode 100644 index 0000000..f96dba2 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickCollectionFilterTime.java @@ -0,0 +1,48 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; + +class TickCollectionFilterTime extends AbstractCollection { + + private final Collection all; + private final int timeLimitMinute; + + TickCollectionFilterTime(Collection all, int timeLimitMinute) { + this.all = all; + this.timeLimitMinute = timeLimitMinute; + } + + public Iterator iterator() { + return new TickFilterIterator(all.iterator(), timeLimitMinute); + } + + public int size() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/TickDatabase.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickDatabase.java new file mode 100644 index 0000000..b20f567 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickDatabase.java @@ -0,0 +1,97 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingDeque; + +import net.sourceforge.plantuml.pstat.event.StatEvent; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlCreate; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlLoadImage; +import net.sourceforge.plantuml.pstat.event.StatEventHtmlLoadPage; +import net.sourceforge.plantuml.pstat.event.StatEventImageGeneration; + +public class TickDatabase { + + private final LinkedBlockingDeque all = new LinkedBlockingDeque(); + private final ConcurrentHashMap browser = new ConcurrentHashMap(); + private final ConcurrentHashMap dailyStats = new ConcurrentHashMap(); + + public void updateStats(StatEvent ev) { + if (ev instanceof StatEventImageGeneration) { + final StatEventImageGeneration ev2 = (StatEventImageGeneration) ev; + final TickImageGeneration tick = new TickImageGeneration(ev2); + final int duration = tick.getDuration(); + if (duration > 0) { + all.add(tick); + } + final Day day = new Day(ev2.getStartServerTime()); + DailyStat dailyStat = dailyStats.get(day); + if (dailyStat == null) { + dailyStat = new DailyStat(); + final DailyStat old = dailyStats.putIfAbsent(day, dailyStat); + if (old != null) { + dailyStat = old; + } + } + dailyStat.updateStats(ev2); + } else if (ev instanceof StatEventHtmlLoadImage || ev instanceof StatEventHtmlLoadPage + || ev instanceof StatEventHtmlCreate) { + final String token = getToken(ev); + TickBrowser tickBrowser = browser.get(token); + if (tickBrowser == null) { + tickBrowser = new TickBrowser(ev); + final TickBrowser old = browser.putIfAbsent(token, tickBrowser); + if (old != null) { + tickBrowser = old; + } + } + tickBrowser.update(ev); + + } + + } + + static private String getToken(StatEvent ev) { + if (ev instanceof StatEventHtmlLoadImage) { + return ((StatEventHtmlLoadImage) ev).getToken(); + } + if (ev instanceof StatEventHtmlLoadPage) { + return ((StatEventHtmlLoadPage) ev).getToken(); + } + if (ev instanceof StatEventHtmlCreate) { + return ((StatEventHtmlCreate) ev).getToken(); + } + throw new IllegalArgumentException(); + } + + public GraphData getGraphData() { + return new GraphData(all.iterator(), browser.values().iterator()); + } + + public GraphDataLongTerm getGraphDataLongTerm() { + return new GraphDataLongTerm(dailyStats.entrySet().iterator()); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/TickFilterIterator.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickFilterIterator.java new file mode 100644 index 0000000..1ce0afe --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickFilterIterator.java @@ -0,0 +1,68 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +class TickFilterIterator implements Iterator { + + private final Iterator it; + private final int timeLimitMinute; + private TickImageGeneration potentialNext; + + TickFilterIterator(Iterator it, int timeLimitMinute) { + this.it = it; + this.timeLimitMinute = timeLimitMinute; + this.potentialNext = getPotentialNext(); + } + + private TickImageGeneration getPotentialNext() { + while (it.hasNext()) { + potentialNext = it.next(); + if (potentialNext.getStartMinute() >= timeLimitMinute) { + return potentialNext; + } + } + return null; + } + + public boolean hasNext() { + return potentialNext != null; + } + + public TickImageGeneration next() { + if (potentialNext == null) { + throw new NoSuchElementException(); + } + final TickImageGeneration result = potentialNext; + potentialNext = getPotentialNext(); + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/tick/TickImageGeneration.java b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickImageGeneration.java new file mode 100644 index 0000000..2b55e2e --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/tick/TickImageGeneration.java @@ -0,0 +1,102 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.tick; + +import java.util.Date; + +import net.sourceforge.plantuml.pstat.event.StatEventImageGeneration; + +public class TickImageGeneration { + + private final String country; + private final String acceptLanguage; + private final String browser; + private final String operatingSystem; + private final String referer; + private final String type; + private final String incomming; + private final String host; + private final int startMinute; + private final int duration; + + public TickImageGeneration(StatEventImageGeneration stat) { + this.country = stat.getCountry(); + this.acceptLanguage = stat.getAcceptLanguage(); + this.browser = stat.getBrowser(); + this.operatingSystem = stat.getOperatingSystem(); + this.referer = stat.getReferer(); + this.incomming = stat.getIncomming(); + this.host = stat.getHost(); + this.type = stat.getType(); + this.startMinute = (int) (stat.getStartServerTime() / 1000L / 60); + this.duration = stat.getDuration(); + + } + + @Override + public String toString() { + return "tick " + new Date(startMinute * 1000L * 60).toGMTString(); + } + + public final String getCountry() { + return country; + } + + public final String getAcceptLanguage() { + return acceptLanguage; + } + + public final String getBrowser() { + return browser; + } + + public final String getOperatingSystem() { + return operatingSystem; + } + + public final String getReferer() { + return referer; + } + + public final String getType() { + return type; + } + + public final int getStartMinute() { + return startMinute; + } + + public final int getDuration() { + return duration; + } + + public final String getIncomming() { + return incomming; + } + + public final String getHost() { + return host; + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/time/DateManager.java b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManager.java new file mode 100644 index 0000000..6c21993 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManager.java @@ -0,0 +1,40 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.time; + +public interface DateManager { + + public static final DateManager DAILY = new DateManagerDaily(); + public static final DateManager HOURLY = new DateManagerHourly(); + public static final DateManager MINUTELY = new DateManagerMinutely(); + public static final DateManager MONTHLY = new DateManagerMonthly(); + public static final DateManager YEARLY = new DateManagerYear(); + + public int toNumber(long date); + + public String getDescription(int number); + + public String getDescriptionShort(int number); + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerDaily.java b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerDaily.java new file mode 100644 index 0000000..8a00389 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerDaily.java @@ -0,0 +1,55 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.time; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +class DateManagerDaily implements DateManager { + + private static final long COEF = 1000L * 3600 * 24; + + public int toNumber(long date) { + final long m = date / COEF; + return (int) m; + } + + // private static DateFormat df = new SimpleDateFormat("yyyy MMM EEE dd", Locale.US); + // private static DateFormat dfShort = new SimpleDateFormat("dd", Locale.US); + + public String getDescription(int number) { + final DateFormat df = new SimpleDateFormat("yyyy MMM EEE dd", Locale.US); + final Date date = new Date(number * COEF); + return df.format(date); + } + + public String getDescriptionShort(int number) { + final DateFormat dfShort = new SimpleDateFormat("dd", Locale.US); + final Date date = new Date(number * COEF); + return dfShort.format(date); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerHourly.java b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerHourly.java new file mode 100644 index 0000000..c3406b4 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerHourly.java @@ -0,0 +1,56 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.time; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +class DateManagerHourly implements DateManager { + + private static final long COEF = 1000L * 3600; + + public int toNumber(long date) { + final long m = date / COEF; + return (int) m; + } + + // private static DateFormat df = new SimpleDateFormat("yyyy MMM EEE dd HH:00", Locale.US); + // private static DateFormat dfShort = new SimpleDateFormat("HH", Locale.US); + + public String getDescription(int number) { + final DateFormat df = new SimpleDateFormat("yyyy MMM EEE dd HH:00", Locale.US); + final Date date = new Date(number * COEF); + return df.format(date); + // return date.toString(); + } + + public String getDescriptionShort(int number) { + final DateFormat dfShort = new SimpleDateFormat("HH", Locale.US); + final Date date = new Date(number * COEF); + return dfShort.format(date); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMinutely.java b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMinutely.java new file mode 100644 index 0000000..ba51910 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMinutely.java @@ -0,0 +1,56 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.time; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +class DateManagerMinutely implements DateManager { + + private static final long COEF = 1000L * 60; + + public int toNumber(long date) { + final long m = date / COEF; + return (int) m; + } + + // private static DateFormat df = new SimpleDateFormat("yyyy MMM EEE dd HH:mm", Locale.US); + // private static DateFormat dfShort = new SimpleDateFormat("mm", Locale.US); + + public String getDescription(int number) { + final DateFormat df = new SimpleDateFormat("yyyy MMM EEE dd HH:mm", Locale.US); + final Date date = new Date(number * COEF); + return df.format(date); + // return date.toString(); + } + + public String getDescriptionShort(int number) { + final DateFormat dfShort = new SimpleDateFormat("mm", Locale.US); + final Date date = new Date(number * COEF); + return dfShort.format(date); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMonthly.java b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMonthly.java new file mode 100644 index 0000000..70c3376 --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerMonthly.java @@ -0,0 +1,52 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.time; + +import java.util.Date; + +class DateManagerMonthly implements DateManager { + + static private final String[] MONTH = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec" }; + + public int toNumber(long d) { + final Date date = new Date(d); + return date.getYear() * 12 + date.getMonth(); + } + + public String getDescription(int number) { + final int month = number % 12; + final int year = number / 12; + return MONTH[month] + " " + (1900 + year); + } + + public String getDescriptionShort(int number) { + final int month = number % 12; + return MONTH[month]; + // final int month = number % 12; + // final int year = number / 12; + // return "" + (year - 100) + "/" + String.format("%02d", month + 1); + } + +} diff --git a/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerYear.java b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerYear.java new file mode 100644 index 0000000..bbcedec --- /dev/null +++ b/src/main/java/net/sourceforge/plantuml/pstat/time/DateManagerYear.java @@ -0,0 +1,44 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +package net.sourceforge.plantuml.pstat.time; + +import java.util.Date; + +class DateManagerYear implements DateManager { + + public int toNumber(long d) { + final Date date = new Date(d); + return date.getYear(); + } + + public String getDescription(int number) { + return "Year " + (1900 + number); + } + + public String getDescriptionShort(int number) { + return "" + (1900 + number); + } + + +}