View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2009 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.util.socketstatistics;
18  
19  import java.io.BufferedWriter;
20  import java.io.FileWriter;
21  import java.io.IOException;
22  import java.util.Date;
23  import java.util.Iterator;
24  import java.util.Set;
25  import java.util.SortedSet;
26  import java.util.TreeSet;
27  
28  /**
29   * Keeps statistics for all sockets / from all socket connections.
30   *
31   * @svnLink $Revision: 3990 $;$Date: 2009-11-13 16:36:10 +0100 (Fr, 13. Nov 2009) $;$Author: jonasha $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/socketstatistics/src/main/java/ch/elca/el4j/util/socketstatistics/SocketStatistics.java $
32   *
33   * @author Jonas Hauenstein (JHN)
34   */
35  public class SocketStatistics implements SocketStatisticsMXBean {
36  
37  	/**
38  	 * Config: How many seconds to keep the statistics of sockets. Default is 600 seconds = 10 minutes
39  	 */
40  	private static int s_keepStats = 600;
41  
42  	/**
43  	 * Internal unique id counter for sockets.
44  	 */
45  	private static long s_socketIdCounter = 0;
46  
47  	/**
48  	 * Number of already closed sockets.
49  	 */
50  	private static long s_nrofclosedsockets = 0;
51  
52  	/**
53  	 * List of all connections sorted by destruction / closed date (first order). and creation date (second order, if
54  	 * not yet closed).
55  	 */
56  	private static SortedSet<ConnectionStatistics> s_statsbydate = new TreeSet<ConnectionStatistics>();
57  
58  	/**
59  	 * Add a new ConnectionStatics for a socket.
60  	 * 
61  	 * @return the ConnectionsStatics added to the the set
62  	 */
63  	public static synchronized ConnectionStatistics addNewConStats() {
64  		// explicitly synchronize on list
65  		synchronized (s_statsbydate) {
66  			long i = getNextID();
67  			ConnectionStatistics cs = new ConnectionStatistics(i);
68  			s_statsbydate.add(cs);
69  			cleanupStats();
70  			return cs;
71  		}
72  	}
73  
74  	/**
75  	 * Fetch next id for socket and increment internal counter.
76  	 * 
77  	 * @return next unique id
78  	 */
79  	private static synchronized long getNextID() {
80  		return ++s_socketIdCounter;
81  	}
82  
83  	/** {@inheritDoc} */
84  	public long getClosedSocketsCount() {
85  		return s_nrofclosedsockets;
86  	}
87  
88  	/** {@inheritDoc} */
89  	public long getOpenSocketsCount() {
90  		return s_socketIdCounter - s_nrofclosedsockets;
91  	}
92  
93  	/** {@inheritDoc} */
94  	public Set<ConnectionStatistics> getConnectionStatistics() {
95  		return new TreeSet<ConnectionStatistics>(s_statsbydate);
96  	}
97  
98  	/** {@inheritDoc} */
99  	public int getKeepStats() {
100 		return s_keepStats;
101 	}
102 
103 	/** {@inheritDoc} */
104 	public void setKeepStats(int ks) {
105 		setKeepStatsS(ks);
106 	}
107 	
108 	/**
109 	 * Internal static setter for the keepStats property which defines how many seconds 
110 	 * stats of closed sockets are kept.
111 	 * 
112 	 * @param ks how many seconds closed sockets will be kept in statistics
113 	 */
114 	private static void setKeepStatsS(int ks) {
115 		s_keepStats = ks;
116 	}
117 
118 	/** {@inheritDoc} */
119 	public void exportStatisticsCSV(String filepath) {
120 		BufferedWriter out = null;
121 		try {
122 			out = new BufferedWriter(new FileWriter(filepath));
123 			out.write("Socket ID;Creation Date;Destruction Date;Remote Adress;Remote Port;Local Port;Bytes received;Bytes sent\n");
124 			synchronized (s_statsbydate) {
125 				for (ConnectionStatistics cs : s_statsbydate) {
126 					out.write(cs.getStatisticsCSV());
127 				}
128 			}
129 		} catch (IOException ex) {
130 			ex.printStackTrace();
131 		} finally {
132 			try {
133 				if (out != null) {
134 					out.flush();
135 					out.close();
136 				}
137 			} catch (IOException ex) {
138 				ex.printStackTrace();
139 			}
140 		}
141 	}
142 
143 	/** {@inheritDoc} */
144 	public void deleteStatistics() {
145 		synchronized (s_statsbydate) {
146 			s_statsbydate.clear();
147 		}
148 	}
149 
150 	/**
151 	 * Set a connection as destroyed / closed. Also sets the destruction date / close date of the connection to now
152 	 * 
153 	 * @param cs
154 	 *            the corresponding ConnectionStatics object
155 	 */
156 	public static synchronized void setConnectionDestroyed(ConnectionStatistics cs) {
157 		// explicitly synchronize on list
158 		synchronized (s_statsbydate) {
159 			// remove element from set
160 			s_statsbydate.remove(cs);
161 			// set the destruction date
162 			cs.setDestroyedDateInt();
163 			s_nrofclosedsockets++;
164 			// re-enter element in set (to force reordering)
165 			s_statsbydate.add(cs);
166 		}
167 	}
168 
169 	/**
170 	 * Print statistics of all listed sockets to stdout.
171 	 */
172 	public void showSocketsStats() {
173 		cleanupStats();
174 		// explicitly synchronize on list
175 		synchronized (s_statsbydate) {
176 			if (s_statsbydate.isEmpty()) {
177 				System.out.println("No statistics available");
178 			} else {
179 				for (ConnectionStatistics cs : s_statsbydate) {
180 					System.out.println(cs.getStatistics());
181 				}
182 			}
183 		}
184 	}
185 
186 	/**
187 	 * Get rid of the old ConnectionStatics. Purge those, which are closed longer ago then keepstats
188 	 */
189 	private static synchronized void cleanupStats() {
190 
191 		// explicitly synchronize on list
192 		synchronized (s_statsbydate) {
193 			ConnectionStatistics cs;
194 			Date dd;
195 			long timecheck = new Date().getTime() - (s_keepStats * 1000);
196 			Iterator<ConnectionStatistics> i = s_statsbydate.iterator();
197 			// remove elements until one does not match the condition in the
198 			// sorted list
199 			while (i.hasNext()) {
200 				cs = i.next();
201 				dd = cs.getDestroyedDateInt();
202 				if (dd != null) {
203 					if (dd.getTime() < timecheck) {
204 						i.remove();
205 					} else {
206 						break;
207 					}
208 				} else {
209 					break;
210 				}
211 			}
212 		}
213 
214 	}
215 
216 }