Java tutorial
/* * Copyright 1999-2006 University of Chicago * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.nimbustools.messaging.gt4_0.common; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.axis.types.Duration; import org.oasis.wsrf.faults.BaseFaultType; import org.globus.wsrf.utils.FaultHelper; import java.util.List; import java.util.LinkedList; @SuppressWarnings("unchecked") public class CommonUtil { private static final Log logger = LogFactory.getLog(CommonUtil.class.getName()); public static final String PRETTY_CAUSES_NUM_KEY = "nimbus.errors.parent.number"; public static final String PRETTY_CAUSES_STACKTRACES = "nimbus.errors.stacktraces"; public static Duration minutesToDuration(int minutes) { /* * false - non-negative duration * 0 years * 0 months * 0 days * 0 hours * # minutes * 0 seconds */ return new Duration(false, 0, 0, 0, 0, minutes, 0); } public static Duration secondsToDuration(int seconds) { /* * false - non-negative duration * 0 years * 0 months * 0 days * 0 hours * 0 minutes * # seconds */ return new Duration(false, 0, 0, 0, 0, 0, seconds); } /** * Converts duration into seconds. The current Duration class * implementation does not support proper <, >, or even equals * operations. Choosing to convert all Durations off to seconds * for comparison rather than extend and fix the Duration class * implementation. * * Max duration is max(int) seconds. This is around ~25k days. * * Assumes years and month are ZERO and negative is FALSE. Years * and months cannot be compared reliably because they can only be * partially ordered. * * TODO: possibly incorporate this restriction into the service schema? * * TODO: what to do if these ints are made to overflow? * * Uses the * {@link Double#doubleToLongBits(double) doubleToLongBits} * method. * * @param dur Positive duration instance w/o years or months. * @return Number of seconds in the Duration instance. * @throws InvalidDurationException problem */ public static int durationToSeconds(Duration dur) throws InvalidDurationException { final int days; final int hours; final int mins; final double secs; final Long longsecs; final int intsecs; if (dur.isNegative()) { throw new InvalidDurationException("Duration can not be negative."); } if (dur.getYears() != 0) { throw new InvalidDurationException("Years in duration must be " + "zero."); } if (dur.getMonths() != 0) { throw new InvalidDurationException("Months in duration must be " + "zero."); } // Convert each to next lowest, until we get to seconds. days = dur.getDays(); hours = dur.getHours() + days * 24; mins = dur.getMinutes() + hours * 60; secs = dur.getSeconds() + mins * 60; // Convert to int longsecs = new Long(new Double(secs).longValue()); intsecs = longsecs.intValue(); if (intsecs == Integer.MAX_VALUE) { throw new InvalidDurationException("Duration can not be " + "longer than ~25k days."); } return intsecs; } /** * Ceilings to nearest minute. * @param dur duration * @return nearest minute (cieling) * @throws InvalidDurationException problem */ public static int durationToMinutes(Duration dur) throws InvalidDurationException { final int seconds = durationToSeconds(dur); return secondsToMinutes(seconds); } // Ceilings to nearest minute. public static int secondsToMinutes(int seconds) { if (seconds == 0) { return 0; } else { int minutes = seconds / 60; if (seconds % 60 > 0) { minutes += 1; } return minutes; } } /** * Buck stops here... Using this mostly to include a message in a * close-to-user exception, where the Throwable gets set to that * exception's cause (for debug mode stacktrace). * * For example: * * <code>throw new Exception(CommonStrings.genericExceptionMessageWrapper(t), t);</code> * * @param any some Throwable you have not dealt with * @return some kind of message, even a non-informative one. * @see #recurseForSomeString(Throwable) */ public static String genericExceptionMessageWrapper(Throwable any) { // Bad if a user ever sees this contingency, always needs fix for the // next release. final String fallback = "[[ Sorry, could not find any problem " + "description. See debugging output for stacktrace and please " + "inform development list, including debugging output if " + "you can."; final String fallback_suffix = " ]]"; if (any == null) { return fallback + fallback_suffix; } String message = any.getMessage(); if (message == null) { message = recurseForSomeString(any); } if (message == null) { message = fallback + " Problem name: \"" + any.getClass().getName() + "\"" + fallback_suffix; } return message; } /** * todo: method description * * Makes use of <code>BaseFaultType</code> awareness, via * <code>#faultString(BaseFaultType)</code> * * @param throwable may be null * @return null or first encountered error description string * @see #faultString(org.oasis.wsrf.faults.BaseFaultType) */ public static String recurseForSomeString(Throwable throwable) { Throwable t = throwable; while (true) { if (t == null) { return null; } String msg = t.getMessage(); if (msg != null) { return msg; // *** RETURN *** } if (t instanceof BaseFaultType) { msg = faultString((BaseFaultType) t); if (msg == null) { t = t.getCause(); } else { return msg; // *** RETURN *** } } else { t = t.getCause(); } } } /** * finds the root cause and prints its error description or if there is no * error description, just its class name * * Makes use of <code>BaseFaultType</code> awareness, via * <code>#faultString(BaseFaultType)</code> * * @param throwable may be null * @param suffixClassChain if true, class names of all errors involved are * tacked on to the string like: [[ classname --> classname --> ...]] * @param numIncludedParentMsgs if suffixClassChain is true, this is the * number of parents up from cause to print the exception messages * for in the chain msg (not just the parent types) * @param lookForSysProp if true, the "nimbus.errors.parent.number" will * be consulted and could possibly override the choice for * numIncludedParentMsgs * @return LAST encountered error description/classname, only null if * input is null (there is neither a type nor message to report) */ public static String recurseForRootString(final Throwable throwable, final boolean suffixClassChain, final int numIncludedParentMsgs, final boolean lookForSysProp) { int realNumIncludedParentMsgs = numIncludedParentMsgs; if (lookForSysProp) { final String numParentsString = System.getProperty(PRETTY_CAUSES_NUM_KEY); try { if (numParentsString != null && numParentsString.trim().length() != 0) { realNumIncludedParentMsgs = Integer.parseInt(numParentsString); } } catch (Throwable t2) { logger.error("Could not parse a number from the '" + PRETTY_CAUSES_NUM_KEY + "' system property."); } } final String alsoStackTracesStr = System.getProperty(PRETTY_CAUSES_STACKTRACES); boolean alsoStackTraces = false; if (alsoStackTracesStr != null && alsoStackTracesStr.trim().equalsIgnoreCase("true")) { alsoStackTraces = true; } final List parentMsgs = new LinkedList(); final List parentTypes = new LinkedList(); final List parentStacktraces = new LinkedList(); final StringBuffer buf = new StringBuffer(); int numDeep = 0; Throwable t = throwable; Throwable lastt = null; while (true) { if (t == null) { return _doneRecursingForRootString(lastt, numDeep, buf, suffixClassChain, parentMsgs, parentTypes, realNumIncludedParentMsgs, alsoStackTraces, parentStacktraces); } numDeep += 1; String thisMsg = t.getMessage(); if (thisMsg == null && t instanceof BaseFaultType) { thisMsg = faultString((BaseFaultType) t); } if (thisMsg == null) { if (t instanceof RuntimeException) { final StringBuffer lilStack = new StringBuffer(); lilStack.append( "No message, but RuntimeException so " + "including part of the stack trace: [[ "); lilStack.append("\n").append(t.getClass().getName()); final StackTraceElement[] runTimeTraces = t.getStackTrace(); for (int i = 0; i < runTimeTraces.length; i++) { final StackTraceElement runTimeTrace = runTimeTraces[i]; lilStack.append("\n\t at ").append(runTimeTrace); if (i == 10) { final int remaining = runTimeTraces.length - i; if (remaining > 0) { lilStack.append("\n ...").append(remaining).append(" more."); } break; } } lilStack.append("\n ]]"); thisMsg = lilStack.toString(); } else { thisMsg = "no message"; } } final String thisType = t.getClass().getName(); final Throwable thisCause = t.getCause(); if (thisCause == null) { lastt = t; t = null; buf.append(thisMsg).append(" (").append(thisType).append(")"); } else { // keep going deeper lastt = t; t = thisCause; parentMsgs.add(thisMsg); parentTypes.add(thisType); parentStacktraces.add(t.getStackTrace()); } } } private static String _doneRecursingForRootString(final Throwable lastt, final int numDeep, final StringBuffer buf, final boolean suffixClassChain, final List parentMsgs, final List parentTypes, final int includedParentMsgs, final boolean alsoStackTraces, final List parentStacktraces) { if (numDeep == 0) { return null; // *** EARLY RETURN *** } if (numDeep == 1) { return buf.toString(); // *** EARLY RETURN *** } final String main = buf.toString(); if (!suffixClassChain) { return main; // *** EARLY RETURN *** } final int numMsgs = parentMsgs.size(); if (numMsgs != parentTypes.size()) { return main + "\n[[**** PROBLEM WITH ATTAINING CAUSE CHAIN: " + "parentMsgs and parentTypes sizes do not match ****]]"; } final StringBuffer retbuf = new StringBuffer(main); retbuf.append("\n[[**** Cause chain report ****]]"); for (int i = 0; i < numMsgs; i++) { retbuf.append("\n "); for (int j = 0; j < i; j++) { retbuf.append(" "); } final String type = (String) parentTypes.get(i); retbuf.append("caused by (#").append(i + 1).append("): ").append(type); } retbuf.append("\n"); int startIncluding = numMsgs - includedParentMsgs; if (startIncluding < 0) { startIncluding = 0; } for (int i = 0; i < numMsgs; i++) { if (i >= startIncluding) { retbuf.append("\n"); final String msg = (String) parentMsgs.get(i); retbuf.append("Message for #").append(i + 1).append(":\n").append(msg); if (includedParentMsgs > 1) { retbuf.append("\n========================================"); } if (alsoStackTraces) { final String thisTraceName = "Stacktrace for #" + (i + 1); retbuf.append("\n\n").append(thisTraceName).append(":\n").append(msg); final StackTraceElement[] traces = (StackTraceElement[]) parentStacktraces.get(i); if (traces == null || traces.length == 0) { retbuf.append(" no stacktrace available (?)"); } else { for (int j = 0; j < traces.length; j++) { final StackTraceElement trace = traces[j]; retbuf.append("\tat ").append(trace).append("\n"); } } retbuf.append("\n(END ").append(thisTraceName).append(")"); if (includedParentMsgs > 1) { retbuf.append("\n========================================"); } retbuf.append("\n"); } } } retbuf.append("\n\nOriginal message:\n").append(main); if (alsoStackTraces) { retbuf.append("\nStacktrace for original problem: "); if (lastt == null) { retbuf.append(" no throwable available (?)"); } else { final StackTraceElement[] traces = lastt.getStackTrace(); if (traces == null || traces.length == 0) { retbuf.append(" no stacktrace available (?)"); } else { for (int j = 0; j < traces.length; j++) { final StackTraceElement trace = traces[j]; retbuf.append("\tat ").append(trace).append("\n"); } } } retbuf.append("\n(END stacktrace for original problem)"); } retbuf.append("\n[[**** end of cause chain report ****]]\n\n"); return retbuf.toString(); } /** * todo: method description * * @param e may be null * @return null if input is null, first encountered error description, or class name */ public static String faultString(BaseFaultType e) { if (e == null) { return null; } final FaultHelper helper = new FaultHelper(e); final String[] descriptions = helper.getDescription(); if (descriptions == null || descriptions.length == 0) { // Decided that anything recursing into BaseFaultType causes for // strings via #getCause(), such as #recurseForSomeString(), is // not going to find anything. return "Fault without any problem description: " + e.getClass().getName(); } final StringBuffer buf = new StringBuffer(2048); buf.append(descriptions[0]); if (descriptions.length > 1) { for (int i = 1; i < descriptions.length; i++) { buf.append(" || ").append(descriptions[i]); } } return buf.toString(); } }