001    package com.softnetConsult.utils.sys;
002    
003    import java.io.File;
004    import java.io.FileInputStream;
005    import java.io.IOException;
006    
007    import com.softnetConsult.utils.reflect.ClassTools;
008    import com.softnetConsult.utils.reflect.ClassVersionInfo;
009    
010    /**
011     * Static system, memory and time management utility functions.
012     * 
013     * <p style="font-size:smaller;">This product includes software developed by the
014     *    <strong>SoftNet-Consult Java Utility Library</strong> project and its contributors.<br />
015     *    (<a href="http://java-tools.sourceforge.net" target="_blank">http://java-tools.sourceforge.net</a>)<br />
016     *    Copyright (c) 2007-2008 SoftNet-Consult.<br />
017     *    Copyright (c) 2007-2008 G. Paperin.<br />
018     *    All rights reserved.
019     * </p>
020     * <p style="font-size:smaller;">File: SystemTools.java<br />
021     *    Library API version: {@value com.softnetConsult.utils.APIProperties#apiVersion}<br />
022     *    Java compliance version: {@value com.softnetConsult.utils.APIProperties#javaComplianceVersion}
023     * </p>
024     * <p style="font-size:smaller;">Redistribution and use in source and binary forms, with or
025     *    without modification, are permitted provided that the following terms and conditions are met:
026     * </p>
027     * <p style="font-size:smaller;">1. Redistributions of source code must retain the above
028     *    acknowledgement of the SoftNet-Consult Java Utility Library project, the above copyright
029     *    notice, this list of conditions and the following disclaimer.<br />
030     *    2. Redistributions in binary form must reproduce the above acknowledgement of the
031     *    SoftNet-Consult Java Utility Library project, the above copyright notice, this list of
032     *    conditions and the following disclaimer in the documentation and/or other materials
033     *    provided with the distribution.<br />
034     *    3. All advertising materials mentioning features or use of this software or any derived
035     *    software must display the following acknowledgement:<br />
036     *    <em>This product includes software developed by the SoftNet-Consult Java Utility Library
037     *    project and its contributors.</em>
038     * </p>
039     * <p style="font-size:smaller;">THIS SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY
040     *    OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
041     *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL
042     *    THE AUTHORS, CONTRIBUTORS OR COPYRIGHT  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
043     *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM, OUT OF OR
044     *    IN CONNECTION WITH THE SOFTWARE OR THE USE OR  OTHER DEALINGS IN THE SOFTWARE.
045     * </p> 
046     * @author Greg Paperin (<a href="http://www.paperin.org" target="_blank">http://www.paperin.org</a>)
047     * @version {@value com.softnetConsult.utils.APIProperties#apiVersion}
048     *
049     */
050    public final class SystemTools {
051    
052    /**
053     * Prevents instances of this class from being created
054     * as this class contains only static utility methods.
055     */
056    private SystemTools() {}
057    
058    
059    /**
060     * Fetches the current memory information and formats the data in a human readable string.
061     *
062     * @return A human readable string containing information on available free memory, memory
063     * used by the current application, the total memory size of the current JVM and the maximum
064     * amount of memory that the current JVM will attempt to use.
065     */
066    public static String getMemInfoString() {
067            Runtime rt = Runtime.getRuntime();
068            long free = rt.freeMemory();
069            long total = rt.totalMemory();
070            long max = rt.maxMemory();
071            String s = String.format("Memory info: Free: %,d KB; Used: %,d; Total: %,d KB; Max: %,d KB.",
072                                                             free >>> 10, (total - free) >>> 10, total >>> 10, max >>> 10);
073            return s;
074    }
075    
076    
077    /**
078     * Prints a human readable line with the current memory information to std-out,
079     * equivalent to {@code System.out.println(getMemInfoString())}.
080     *
081     */
082    public static void printMemInfoLine() {
083            System.out.println(getMemInfoString());
084    }
085    
086    
087    /**
088     * Allows calling {@code Thread.sleep} without the nuisance of surrounding the call with
089     * a {@code try-catch} block. A possible {@code InterruptedException} is caught and ignored.
090     * 
091     * @param millis The length of time to sleep in milliseconds.
092     */
093    public static void sleep(long millis) {
094            try {
095                    Thread.sleep(millis);
096            } catch(InterruptedException e) { }
097    }
098    
099    
100    /**
101     * Allows calling {@code Thread.sleep} without the nuisance of surrounding the call with
102     * a {@code try-catch} block. A possible {@code InterruptedException} is caught and ignored.
103     * 
104     * @param millis The length of time to sleep in milliseconds.
105     * @param nanos 0-999999 additional nanoseconds to sleep.
106     */
107    public static void sleep(long millis, int nanos) {
108            try {
109                    Thread.sleep(millis, nanos);
110            } catch(InterruptedException e) { }
111    }
112    
113    
114    /**
115     * Allows calling {@code Object.wait} without the nuisance of surrounding the call with
116     * a {@code try-catch} block. A possible {@code InterruptedException} is caught and ignored.
117     * 
118     * @param millis The length of time to sleep in milliseconds.
119     * @param object The object for which to wait.
120     */
121    public static void wait(long millis, Object object) {
122            try {
123                    object.wait(millis);
124            } catch(InterruptedException e) { }
125    }
126    
127    
128    /**
129     * Allows calling {@code Object.wait} without the nuisance of surrounding the call with
130     * a {@code try-catch} block. A possible {@code InterruptedException} is caught and ignored.
131     * 
132     * @param millis The length of time to sleep in milliseconds.
133     * @param nanos 0-999999 additional nanoseconds to sleep.
134     * @param object The object for which to wait.
135     */
136    public static void wait(long millis, int nanos, Object object) {
137            try {
138                    object.wait(millis, nanos);
139            } catch(InterruptedException e) { }
140    }
141    
142    
143    /**
144     * Determines how many days, hours, minutes, seconds and milliseconds the specified time
145     * period contains.
146     * Note that the specified time period, i.e. the absolude difference between {@code startMillis}
147     * and {@code endMillis} may not be larger than {@code 185542587187199999L} milliseconds, as an internal
148     * overflow would occur otherwise. The limit of {@code 185542587187199999L milliseconds} corrsponds to
149     * {@code ( (Integer.MAX_VALUE + 1L) * 86400000L - 1L ) milliseconds} or
150     * {@code Integer.MAX_VALUE days, 23 hours, 59 minures and 59.999 seconds} or  
151     * {@code 2147483647 days, 23:59:59.999}.
152     * 
153     * @param startMillis The milliseconds marking the beginning of a time period.
154     * @param endMillis The milliseconds marking the end of a time period.
155     * 
156     * @return An {@code int}-array containg exactly 5 following elements:<br />
157     * index {@code [4]}: number of whole days in the specified time period;<br /> 
158     * index {@code [3]}: number of whole hours not covered by the whole days in the specified time period;<br />
159     * index {@code [2]}: number of whole minutes not covered by the whole hours in the specified time period;<br />
160     * index {@code [1]}: number of whole seconds not covered by the whole mins in the specified time period;<br />
161     * index {@code [0]}: number of whole millisecs not covered by the whole secs in the specified time period;<br />
162     * 
163     * @throws IllegalArgumentException If the absolute value of the difference between {@code startMillis}
164     * and {@code endMillis} is larger than {@code 185542587187199999L}.
165     */
166    public static int[] timePeriod(long startMillis, long endMillis) {
167            
168            long period = endMillis - startMillis;
169            if (0L > period)
170                    period = -period;
171            
172            if (period > 185542587187199999L)  // 185542587187199999L = (Integer.MAX_VALUE + 1L) * 86400000L - 1L
173                    throw new IllegalArgumentException("Cannot split a time period of longer "
174                                                                                     + "than 185542587187199999L milliseconds");
175            
176            int[] dets = new int[5];
177            dets[4] = (int) (period / 86400000L);   // days
178            period = period % 86400000L;
179            dets[3] = (int) (period / 3600000L);    // hours
180            period = period  % 3600000L;    
181            dets[2] = (int) (period / 60000L);              // mins
182            period = period % 60000L;       
183            dets[1] = (int) (period / 1000L);               // secs 
184            dets[0] = (int) (period % 1000L);               // millis
185            return dets;
186    }
187    
188    
189    /**
190     * Formats a time interval to a nicely readable format without the need
191     * to involve a formatter. No validity checks are performed.
192     * 
193     * @param millis Milliseconds
194     * @param secs Seconds.
195     * @param mins Minutes.
196     * @param hours Hours.
197     * @param days Days. 
198     * @return Time formated as in for example {@code 3 days, 17:08:53.006}.
199     */
200    public static String formatTime(int millis, int secs, int mins, int hours, int days) {
201            
202            millis = (millis < 0 ? -millis : millis);
203            secs =   (secs < 0 ?   -secs   : secs);
204            mins =   (mins < 0 ?   -mins   : mins);
205            hours =  (hours < 0 ?  -hours  : hours);
206            days =   (days < 0 ?   -days   : days);
207            
208            if (days > 1) {
209                    return String.format("%d days, %02d:%02d:%02d.%03d",
210                                                             days, hours, mins, secs, millis);
211            } else if (days == 1) {
212                    return String.format("1 day, %02d:%02d:%02d.%03d",
213                                                             hours, mins, secs, millis);
214            } else {
215                    return String.format("%02d:%02d:%02d.%03d",
216                                                             hours, mins, secs, millis);
217            }
218    }
219    
220    
221    /**
222     * Formats the specified time period as specified in {@link #formatTime(int, int, int, int, int)};
223     * note that {@link #timePeriod(long, long)} is used to process the time period and therefore the
224     * same restrictions as in that method apply to this method.
225     *  
226     * @param startMillis The milliseconds marking the beginning of a time period.
227     * @param endMillis The milliseconds marking the end of a time period.
228     * @return Time period formated as in for example {@code 3 days, 17:08:53.006}.
229     * @see #timePeriod(long, long)
230     * @see #formatTime(int, int, int, int, int)
231     */
232    public static String formatTimePeriod(long startMillis, long endMillis) {
233            int[] timeDets = timePeriod(startMillis, endMillis);
234            return formatTime(timeDets[0], timeDets[1], timeDets[2], timeDets[3], timeDets[4]);
235    }
236    
237    
238    /**
239     * Gets the class version info of the specified Java class file.
240     * 
241     * @param classfile A {@code File} representing a physical Java class file. 
242     * @return A {@code ClassVersionInfo}-object containing information about the
243     * major and the minor versions of the specified class file as well as the minimum
244     * JVM version required to run that class file. If the specified file is not a valid
245     * Java class file (according to the magic numer check) this method returns {@code null}.
246     * @throws IOException If there was an error when reading the specified file.
247     */
248    public static ClassVersionInfo getClassVersionInfo(File classfile) throws IOException {
249            FileInputStream in = new FileInputStream(classfile);
250            try             { return ClassTools.getClassVersionInfo(in); }
251            finally { in.close(); }
252    }
253    
254    /**
255     * Gets the class version info of the specified Java class file.
256     * 
257     * @param classfile The full path of a physical Java class file. 
258     * @return A {@code ClassVersionInfo}-object containing information about the
259     * major and the minor versions of the specified class file as well as the minimum
260     * JVM version required to run that class file. If the specified file is not a valid
261     * Java class file (according to the magic numer check) this method returns {@code null}.
262     * @throws IOException If there was an error when reading the specified file.
263     */
264    public static ClassVersionInfo getClassVersionInfo(String classfile) throws IOException {
265            FileInputStream in = new FileInputStream(classfile);
266            try             { return ClassTools.getClassVersionInfo(in); }
267            finally { in.close(); }
268    }
269    
270    } // public class SystemTools