001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: SMSException.java,v 1.7 2009/01/28 05:35:03 ww203982 Exp $
026 *
027 */
028
029/*
030 * Portions Copyrighted [2011] [ForgeRock AS]
031 */
032package com.sun.identity.sm;
033
034import com.sun.identity.authentication.internal.InvalidAuthContextException;
035import com.sun.identity.shared.debug.Debug;
036import com.sun.identity.shared.locale.AMResourceBundleCache;
037import com.sun.identity.shared.locale.L10NMessage;
038import com.sun.identity.shared.locale.Locale;
039import com.iplanet.am.sdk.AMException;
040import com.iplanet.services.ldap.LDAPServiceException;
041import com.iplanet.services.ldap.event.EventException;
042import com.iplanet.services.util.XMLException;
043import com.iplanet.sso.SSOException;
044import com.iplanet.ums.IUMSConstants;
045import java.io.PrintWriter;
046import java.io.StringWriter;
047import java.text.MessageFormat;
048import java.util.ResourceBundle;
049import com.sun.identity.shared.ldap.LDAPException;
050
051/**
052 * The exception class whose instance is thrown if there is any error during the
053 * operation of objects of the <code>com.sun.identity.sms</code> package. This
054 * class maps the exception that occurred at a lower level to a high level
055 * error. Using the exception status code <code>getExceptionCode()</code> the
056 * errors are categorized as a <code>ABORT</code>, <code>RETRY</code>,
057 * <code>CONFIG_PROBLEM</code> or <code>LDAP_OP_FAILED</code> (typically a
058 * bug).
059 *
060 * @supported.all.api
061 */
062public class SMSException extends Exception implements L10NMessage {
063
064    transient AMResourceBundleCache amCache = AMResourceBundleCache.getInstance();
065
066    transient Debug debug = Debug.getInstance(IUMSConstants.UMS_DEBUG);
067
068    private int exceptionStatus = STATUS_NONE;
069
070    private Throwable rootCause;
071
072    private String message;
073
074    private String bundleName = IUMSConstants.UMS_BUNDLE_NAME;
075
076    private String errorCode;
077
078    private Object[] args;
079
080    /**
081     * Default constructor for <code> SMSException </code>
082     */
083    public SMSException() {
084        super();
085        exceptionStatus = STATUS_NONE;
086    }
087
088    /**
089     * @param status
090     *            The exception status code.
091     * @param errorCode
092     *            Key to resource bundle.
093     */
094    public SMSException(int status, String errorCode) {
095        super();
096        exceptionStatus = status;
097        this.errorCode = errorCode;
098        this.message = getL10NMessage(java.util.Locale.ENGLISH);
099    }
100
101    /**
102     * @param status
103     *            The Exception status code.
104     * @param exMessage
105     *            The message provided by the object which is throwing the
106     *            exception
107     * @param errorCode
108     *            Key to resource bundle.
109     */
110    public SMSException(int status, String exMessage, String errorCode) {
111        exceptionStatus = status;
112        this.errorCode = errorCode;
113        this.message = exMessage + ": " +
114            getL10NMessage(java.util.Locale.ENGLISH);
115    }
116
117    /**
118     * @param msg
119     *            The message provided by the object which is throwing the
120     *            exception
121     */
122    public SMSException(String msg) {
123        exceptionStatus = STATUS_NONE;
124        this.message = msg;
125    }
126
127    /**
128     * @param msg
129     *            The message provided by the object which is throwing the
130     *            exception
131     * @param errorCode
132     *            Key to resource bundle.
133     */
134    public SMSException(String msg, String errorCode) {
135        exceptionStatus = STATUS_NONE;
136        this.errorCode = errorCode;
137        this.message = msg + ": " + getL10NMessage(java.util.Locale.ENGLISH);
138    }
139
140    /**
141     * Constructs an <code>SMSException</code>.
142     * 
143     * @param t
144     *            The <code>Throwable</code> object provided by the object
145     *            which is throwing the exception
146     * @param errorCode
147     *            Key to resource bundle.
148     */
149    public SMSException(Throwable t, String errorCode) {
150        // super(t); (can be used with JDK 1.4 and higher)
151        rootCause = t;
152        this.errorCode = errorCode;
153        this.message = getL10NMessage(java.util.Locale.ENGLISH);
154        exceptionMapper();
155    }
156
157    /**
158     * Constructs an <code>SMSException</code>.
159     * 
160     * @param message
161     *            exception message.
162     * @param t
163     *            The <code>Throwable</code> object provided by the object
164     *            which is throwing the exception.
165     * @param errorCode
166     *            Key to resource bundle.
167     */
168    public SMSException(String message, Throwable t, String errorCode) {
169        // super(message, t); (can be used with JDK 1.4 and higher)
170        rootCause = t;
171        this.errorCode = errorCode;
172        this.message = message + ": " +
173            getL10NMessage(java.util.Locale.ENGLISH);
174        exceptionMapper();
175    }
176
177    /**
178     * Constructs an <code>SMSException</code>.
179     * 
180     * @param rbName
181     *            Resource bundle Name to be used for getting localized error
182     *            message.
183     * @param message
184     *            exception message.
185     * @param t
186     *            The <code>Throwable</code> object provided by the object
187     *            which is throwing the exception.
188     * @param errorCode
189     *            Key to resource bundle.
190     */
191    public SMSException(String rbName, String message, Throwable t,
192            String errorCode) {
193        // super(message, t); (can be used with JDK 1.4 and higher)
194        rootCause = t;
195        this.errorCode = errorCode;
196        this.bundleName = rbName;
197        this.message = message + ": " +
198            getL10NMessage(java.util.Locale.ENGLISH);
199        if (rootCause != null && !(rootCause instanceof AMException)) {
200            exceptionMapper();
201        }
202    }
203
204    /**
205     * This constructor is used to pass the localized error message At this
206     * level, the locale of the caller is not known and it is not possible to
207     * throw localized error message at this level. Instead this constructor
208     * provides Resource Bundle name and error code for correctly locating the
209     * error message. The default <code>getMessage()</code> will always return
210     * English messages only. This is in consistent with current JRE.
211     * 
212     * @param rbName
213     *            Resource bundle Name to be used for getting localized error
214     *            message.
215     * @param errorCode
216     *            Key to resource bundle. You can use <code>ResourceBundle rb =
217     *        ResourceBunde.getBundle(rbName,locale);
218     *        String localizedStr = rb.getString(errorCode)</code>.
219     * @param args
220     *            arguments to message. If it is not present pass the as null.
221     */
222    public SMSException(String rbName, String errorCode, Object[] args) {
223        exceptionStatus = STATUS_NONE;
224        this.bundleName = rbName;
225        this.errorCode = errorCode;
226        this.args = args;
227        this.message = getL10NMessage(java.util.Locale.ENGLISH);
228    }
229
230    /**
231     * Returns a localized error message
232     * 
233     * @param locale
234     *            Uses the locale object to create the appropriate localized
235     *            error message
236     * @return localized error message.
237     * @see #SMSException(String, String, Object[])
238     */
239    public String getL10NMessage(java.util.Locale locale) {
240        String result = errorCode;
241        if (bundleName != null && locale != null) {
242            ResourceBundle bundle = amCache.getResBundle(bundleName, locale);
243            String mid = Locale.getString(bundle, errorCode, debug);
244            if (args == null || args.length == 0) {
245                result = mid;
246            } else {
247                result = MessageFormat.format(mid, args);
248            }
249        }
250        return result;
251    }
252
253    /**
254     * Returns <code>ResourceBundle</code> Name associated with this error
255     * message.
256     * 
257     * @return <code>ResourceBundle</code> name associated with this error
258     *         message.
259     * @see #SMSException(String, String, Object[])
260     */
261    public String getResourceBundleName() {
262        return bundleName;
263    }
264
265    /**
266     * Returns error code associated with this error message.
267     * 
268     * @return Error code associated with this error message.
269     * @see #SMSException(String, String, Object[])
270     */
271    public String getErrorCode() {
272        return errorCode;
273    }
274
275    /**
276     * Returns arguments for formatting this error message.
277     * 
278     * @return arguments for formatting this error message. You need to use
279     *         <code>MessageFormat</code> class to format the message It can
280     *         be null.
281     * @see #SMSException(String, String, Object[])
282     */
283    public Object[] getMessageArgs() {
284        return args;
285    }
286
287    /**
288     * Returns the status code for this exception.
289     * 
290     * @return Integer representing the exception status code
291     */
292    public int getExceptionCode() {
293        return exceptionStatus;
294    }
295
296    /**
297     * The this package can set the exception code.
298     * 
299     * @param status
300     *            The exception status code.
301     */
302    void setExceptionCode(int status) {
303        exceptionStatus = status;
304    }
305
306    public String toString() {
307        StringBuilder buf = new StringBuilder();
308        if (exceptionStatus != -1) {
309            buf.append("SMSException Exception Code:");
310            buf.append(exceptionStatus);
311            buf.append('\n');
312        }
313        String msg = message;
314        if (msg != null && msg.length() > 0) {
315            buf.append("Message:");
316            buf.append(msg);
317            buf.append("\n");
318        }
319
320        if (rootCause != null) {
321            buf.append("--------------------------------------------------\n");
322            buf.append("The lower level exception message\n");
323            buf.append(rootCause.getMessage());
324            buf.append('\n');
325            buf.append("The lower level exception:\n");
326            StringWriter sw = new StringWriter(100);
327            rootCause.printStackTrace(new PrintWriter(sw));
328            buf.append(sw.toString());
329            buf.append('\n');
330        }
331        return buf.toString();
332    }
333
334    /**
335     * Returns the error message of this exception.
336     * 
337     * @return String representing the error message
338     */
339    public String getMessage() {
340        return message;
341    }
342
343    private String getString(String msgID) {
344        errorCode = msgID;
345        ResourceBundle bundle = null;
346        if (bundleName != null) {
347            bundle = amCache.getResBundle(bundleName, java.util.Locale.ENGLISH);
348        }
349        return (Locale.getString(bundle, msgID, debug));
350    }
351
352    private void exceptionMapper() {
353        if (rootCause == null) {
354            return;
355        }
356        if (rootCause instanceof LDAPException) {
357            message = mapLDAPException();
358        } else if (rootCause instanceof LDAPServiceException) {
359            // do nothing
360        } else if (rootCause instanceof EventException) {
361            exceptionStatus = STATUS_ABORT;
362            message = getString(IUMSConstants.SMS_EVENT_NOTIFICATION_FAILED);
363        } else if (rootCause instanceof XMLException) {
364            exceptionStatus = STATUS_ABORT;
365            message = getString(IUMSConstants.SMS_XML_PARSER_EXCEPTION);
366        } else if (rootCause instanceof InvalidAuthContextException) {
367            message = getString(IUMSConstants.SMS_AUTHENTICATION_ERROR);
368            exceptionStatus = STATUS_ABORT;
369        } else if (rootCause instanceof SSOException) {
370            message = getString(IUMSConstants.SMS_AUTHENTICATION_ERROR);
371            exceptionStatus = STATUS_ABORT;
372        } else {
373            message = getString(IUMSConstants.SMS_UNKNOWN_EXCEPTION_OCCURRED);
374            exceptionStatus = STATUS_UNKNOWN_EXCEPTION;
375        }
376    }
377
378    private String mapLDAPException() {
379        int resultCode = ((LDAPException) rootCause).getLDAPResultCode();
380
381        String message = null;
382
383        switch (resultCode) {
384        // ////////////////////////////////
385        // Errors that need to be handled
386        // ////////////////////////////////
387
388        // Helpless errors
389        // All errors are helpless situations
390        // but some are more helpless than the others.
391        // These errors are either problems in connection
392        // or configuration. So, some can be retired and
393        // some are already busted.
394        case LDAPException.SERVER_DOWN:
395        case LDAPException.OTHER:
396            message = getString(IUMSConstants.SMS_SERVER_DOWN);
397            exceptionStatus = STATUS_RETRY;
398            break;
399        case LDAPException.LDAP_NOT_SUPPORTED:
400            message = getString(IUMSConstants.SMS_LDAP_NOT_SUPPORTED);
401            exceptionStatus = STATUS_ABORT;
402            break;
403        case LDAPException.BUSY:
404            message = getString(IUMSConstants.SMS_LDAP_SERVER_BUSY);
405            exceptionStatus = STATUS_RETRY;
406            break;
407
408        case LDAPException.INVALID_CREDENTIALS:
409            message = getString("INVALID_CREDENTIALS");
410            exceptionStatus = STATUS_CONFIG_PROBLEM;
411            break;
412
413        // Application must show exactly what is happening
414        case LDAPException.NO_SUCH_OBJECT:
415            message = getString(IUMSConstants.SMS_NO_SUCH_OBJECT);
416            exceptionStatus = STATUS_LDAP_OP_FAILED;
417            break;
418
419        case LDAPException.INSUFFICIENT_ACCESS_RIGHTS:
420            message = getString(IUMSConstants.SMS_INSUFFICIENT_ACCESS_RIGHTS);
421            exceptionStatus = STATUS_NO_PERMISSION;
422            break;
423
424        case LDAPException.ADMIN_LIMIT_EXCEEDED:
425            message = getString(IUMSConstants.SMS_ADMIN_LIMIT_EXCEEDED);
426            exceptionStatus = STATUS_ABORT;
427            break;
428
429        case LDAPException.TIME_LIMIT_EXCEEDED:
430            message = getString(IUMSConstants.SMS_TIME_LIMIT_EXCEEDED);
431            exceptionStatus = STATUS_ABORT;
432            break;
433
434        case LDAPException.REFERRAL:
435            message = getString(IUMSConstants.SMS_LDAP_REFERRAL_EXCEPTION);
436            exceptionStatus = STATUS_CONFIG_PROBLEM;
437            break;
438
439        // We screwed up with something
440        case LDAPException.OBJECT_CLASS_VIOLATION:
441        case LDAPException.NAMING_VIOLATION:
442        case LDAPException.CONSTRAINT_VIOLATION:
443        case LDAPException.INVALID_DN_SYNTAX:
444        case LDAPException.ENTRY_ALREADY_EXISTS:
445        case LDAPException.ATTRIBUTE_OR_VALUE_EXISTS:
446        case LDAPException.PROTOCOL_ERROR:
447        case LDAPException.UNDEFINED_ATTRIBUTE_TYPE:
448            SMSEntry.debug.error(rootCause.toString());
449            message = getString(IUMSConstants.SMS_LDAP_OPERATION_FAILED);
450            exceptionStatus = STATUS_LDAP_OP_FAILED;
451            break;
452
453        // Exception code that means logical operation.
454        case LDAPException.COMPARE_TRUE:
455        case LDAPException.COMPARE_FALSE:
456        case LDAPException.LDAP_PARTIAL_RESULTS:
457            exceptionStatus = STATUS_QUO_ANTE;
458            break;
459
460        default:
461            message = getString(IUMSConstants.SMS_UNEXPECTED_LDAP_EXCEPTION);
462            exceptionStatus = STATUS_UNKNOWN_EXCEPTION;
463        }
464        return message;
465    }
466
467    // Error codes
468    /** No status code is set */
469    public static final int STATUS_NONE = -1;
470
471    /** Retry connection to data store */
472    public static final int STATUS_RETRY = 0;
473
474    /** Repeated retry to data store failed */
475    public static final int STATUS_REPEATEDLY_FAILED = 0;
476
477    /** Status to abort operation */
478    public static final int STATUS_ABORT = 1;
479
480    /**
481     * If root LDAP cause is <code>LDAP_PARTIAL_RESULTS </code> then this
482     * status is set
483     */
484    public static final int STATUS_QUO_ANTE = 2;
485
486    /**
487     * If root LDAP cause is an LDAP exception with one of the following error
488     * codes then this status is set.
489     * <p>
490     * 
491     * <PRE>
492     * 
493     * NO_SUCH_OBJECT OBJECT_CLASS_VIOLATION NAMING_VIOLATION
494     * CONSTRAINT_VIOLATION INVALID_DN_SYNTAX ENTRY_ALREADY_EXISTS
495     * ATTRIBUTE_OR_VALUE_EXISTS PROTOCOL_ERROR UNDEFINED_ATTRIBUTE_TYPE
496     * 
497     * </PRE>
498     */
499
500    public static final int STATUS_LDAP_OP_FAILED = 3;
501
502    /**
503     * If the root LDAP exception is <code> INVALID_CREDENTIALS </code> or
504     * <code> REFERRAL </code> then this status is set
505     */
506    public static final int STATUS_CONFIG_PROBLEM = 4;
507
508    /** If root cause is other than any of those listed in other status codes */
509    public static final int STATUS_UNKNOWN_EXCEPTION = 5;
510
511    /** If the root LDAP cause is <code> INSUFFICIENT_ACCESS_RIGHTS </code> */
512    public static final int STATUS_NO_PERMISSION = 8;
513
514    /** the operation is not allowed. */
515    public static final int STATUS_NOT_ALLOW = 9;
516
517}




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.