001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.extensions;
028    
029    
030    
031    import java.io.BufferedReader;
032    import java.io.File;
033    import java.io.FileReader;
034    import java.util.HashMap;
035    import java.util.LinkedList;
036    import java.util.List;
037    import java.util.Properties;
038    import java.util.Set;
039    
040    import org.opends.messages.Message;
041    import org.opends.messages.MessageBuilder;
042    import org.opends.server.admin.server.ConfigurationChangeListener;
043    import org.opends.server.admin.std.server.AccountStatusNotificationHandlerCfg;
044    import org.opends.server.admin.std.server.
045                SMTPAccountStatusNotificationHandlerCfg;
046    import org.opends.server.api.AccountStatusNotificationHandler;
047    import org.opends.server.config.ConfigException;
048    import org.opends.server.core.DirectoryServer;
049    import org.opends.server.loggers.debug.DebugTracer;
050    import org.opends.server.types.AccountStatusNotification;
051    import org.opends.server.types.AccountStatusNotificationProperty;
052    import org.opends.server.types.AccountStatusNotificationType;
053    import org.opends.server.types.Attribute;
054    import org.opends.server.types.AttributeType;
055    import org.opends.server.types.AttributeValue;
056    import org.opends.server.types.ConfigChangeResult;
057    import org.opends.server.types.DebugLogLevel;
058    import org.opends.server.types.Entry;
059    import org.opends.server.types.InitializationException;
060    import org.opends.server.types.ResultCode;
061    import org.opends.server.util.EMailMessage;
062    
063    import static org.opends.messages.ExtensionMessages.*;
064    import static org.opends.server.loggers.ErrorLogger.*;
065    import static org.opends.server.loggers.debug.DebugLogger.*;
066    import static org.opends.server.util.StaticUtils.*;
067    
068    
069    
070    /**
071     * This class provides an implementation of an account status notification
072     * handler that can send e-mail messages via SMTP to end users and/or
073     * administrators whenever an account status notification occurs.  The e-mail
074     * messages will be generated from template files, which contain the information
075     * to use to create the message body.  The template files may contain plain
076     * text, in addition to the following tokens:
077     * <UL>
078     *   <LI>%%notification-type%% -- Will be replaced with the name of the
079     *       account status notification type for the notification.</LI>
080     *   <LI>%%notification-message%% -- Will be replaced with the message for the
081     *       account status notification.</LI>
082     *   <LI>%%notification-user-dn%% -- Will be replaced with the string
083     *       representation of the DN for the user that is the target of the
084     *       account status notification.</LI>
085     *   <LI>%%notification-user-attr:attrname%% -- Will be replaced with the value
086     *       of the attribute specified by attrname from the user's entry.  If the
087     *       specified attribute has multiple values, then the first value
088     *       encountered will be used.  If the specified attribute does not have any
089     *       values, then it will be replaced with an emtpy string.</LI>
090     *   <LI>%%notification-property:propname%% -- Will be replaced with the value
091     *       of the specified notification property from the account status
092     *       notification.  If the specified property has multiple values, then the
093     *       first value encountered will be used.  If the specified property does
094     *       not have any values, then it will be replaced with an emtpy
095     *       string.</LI>
096     * </UL>
097     */
098    public class SMTPAccountStatusNotificationHandler
099           extends AccountStatusNotificationHandler
100                        <SMTPAccountStatusNotificationHandlerCfg>
101           implements ConfigurationChangeListener
102                           <SMTPAccountStatusNotificationHandlerCfg>
103    {
104      /**
105       * The tracer object for the debug logger.
106       */
107      private static final DebugTracer TRACER = getTracer();
108    
109    
110    
111      // A mapping between the notification types and the message template.
112      private HashMap<AccountStatusNotificationType,
113                      List<NotificationMessageTemplateElement>> templateMap;
114    
115      // A mapping between the notification types and the message subject.
116      private HashMap<AccountStatusNotificationType,String> subjectMap;
117    
118      // The current configuration for this account status notification handler.
119      private SMTPAccountStatusNotificationHandlerCfg currentConfig;
120    
121    
122    
123      /**
124       * Creates a new, uninitialized instance of this account status notification
125       * handler.
126       */
127      public SMTPAccountStatusNotificationHandler()
128      {
129        super();
130      }
131    
132    
133    
134      /**
135       * {@inheritDoc}
136       */
137      public void initializeStatusNotificationHandler(
138                       SMTPAccountStatusNotificationHandlerCfg configuration)
139             throws ConfigException, InitializationException
140      {
141        currentConfig = configuration;
142        currentConfig.addSMTPChangeListener(this);
143    
144        subjectMap  = parseSubjects(configuration);
145        templateMap = parseTemplates(configuration);
146    
147        // Make sure that the Directory Server is configured with information about
148        // one or more mail servers.
149        List<Properties> propList = DirectoryServer.getMailServerPropertySets();
150        if ((propList == null) || propList.isEmpty())
151        {
152          throw new ConfigException(ERR_SMTP_ASNH_NO_MAIL_SERVERS_CONFIGURED.get(
153                                         configuration.dn().toString()));
154        }
155    
156        // Make sure that either an explicit recipient list or a set of email
157        // address attributes were provided.
158        Set<AttributeType> mailAttrs = configuration.getEmailAddressAttributeType();
159        Set<String> recipients = configuration.getRecipientAddress();
160        if (((mailAttrs == null) || mailAttrs.isEmpty()) &&
161            ((recipients == null) || recipients.isEmpty()))
162        {
163          throw new ConfigException(ERR_SMTP_ASNH_NO_RECIPIENTS.get(
164                                         configuration.dn().toString()));
165        }
166      }
167    
168    
169    
170      /**
171       * Examines the provided configuration and parses the message subject
172       * information from it.
173       *
174       * @param  configuration  The configuration to be examined.
175       *
176       * @return  A mapping between the account status notification type and the
177       *          subject that should be used for messages generated for
178       *          notifications with that type.
179       *
180       * @throws  ConfigException  If a problem occurs while parsing the subject
181       *                           configuration.
182       */
183      private HashMap<AccountStatusNotificationType,String> parseSubjects(
184                   SMTPAccountStatusNotificationHandlerCfg configuration)
185              throws ConfigException
186      {
187        HashMap<AccountStatusNotificationType,String> map =
188             new HashMap<AccountStatusNotificationType,String>();
189    
190        for (String s : configuration.getMessageSubject())
191        {
192          int colonPos = s.indexOf(':');
193          if (colonPos < 0)
194          {
195            throw new ConfigException(ERR_SMTP_ASNH_SUBJECT_NO_COLON.get(s,
196                                           configuration.dn().toString()));
197          }
198    
199          String notificationTypeName = s.substring(0, colonPos).trim();
200          AccountStatusNotificationType t =
201               AccountStatusNotificationType.typeForName(notificationTypeName);
202          if (t == null)
203          {
204            throw new ConfigException(
205                           ERR_SMTP_ASNH_SUBJECT_INVALID_NOTIFICATION_TYPE.get(
206                                s, configuration.dn().toString(),
207                                notificationTypeName));
208          }
209          else if (map.containsKey(t))
210          {
211            throw new ConfigException(ERR_SMTP_ASNH_SUBJECT_DUPLICATE_TYPE.get(
212                                           configuration.dn().toString(),
213                                           notificationTypeName));
214          }
215    
216          map.put(t, s.substring(colonPos+1).trim());
217          if (debugEnabled())
218          {
219            TRACER.debugInfo("Subject for notification type " + t.getName() +
220                             ":  " + map.get(t));
221          }
222        }
223    
224        return map;
225      }
226    
227    
228    
229      /**
230       * Examines the provided configuration and parses the message template
231       * information from it.
232       *
233       * @param  configuration  The configuration to be examined.
234       *
235       * @return  A mapping between the account status notification type and the
236       *          template that should be used to generate messages for
237       *          notifications with that type.
238       *
239       * @throws  ConfigException  If a problem occurs while parsing the template
240       *                           configuration.
241       */
242      private HashMap<AccountStatusNotificationType,
243                      List<NotificationMessageTemplateElement>> parseTemplates(
244                   SMTPAccountStatusNotificationHandlerCfg configuration)
245              throws ConfigException
246      {
247        HashMap<AccountStatusNotificationType,
248                List<NotificationMessageTemplateElement>> map =
249             new HashMap<AccountStatusNotificationType,
250                          List<NotificationMessageTemplateElement>>();
251    
252        for (String s : configuration.getMessageTemplateFile())
253        {
254          int colonPos = s.indexOf(':');
255          if (colonPos < 0)
256          {
257            throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_NO_COLON.get(s,
258                                           configuration.dn().toString()));
259          }
260    
261          String notificationTypeName = s.substring(0, colonPos).trim();
262          AccountStatusNotificationType t =
263               AccountStatusNotificationType.typeForName(notificationTypeName);
264          if (t == null)
265          {
266            throw new ConfigException(
267                           ERR_SMTP_ASNH_TEMPLATE_INVALID_NOTIFICATION_TYPE.get(
268                                s, configuration.dn().toString(),
269                                notificationTypeName));
270          }
271          else if (map.containsKey(t))
272          {
273            throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_DUPLICATE_TYPE.get(
274                                           configuration.dn().toString(),
275                                           notificationTypeName));
276          }
277    
278          String path = s.substring(colonPos+1).trim();
279          File f = new File(path);
280          if (! f.isAbsolute() )
281          {
282            f = new File(DirectoryServer.getServerRoot() + File.separator +
283                path);
284          }
285          if (! f.exists())
286          {
287            throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_NO_SUCH_FILE.get(
288                                           path, configuration.dn().toString()));
289          }
290    
291          map.put(t, parseTemplateFile(f));
292          if (debugEnabled())
293          {
294            TRACER.debugInfo("Decoded template elment list for type " +
295                             t.getName());
296          }
297        }
298    
299        return map;
300      }
301    
302    
303    
304      /**
305       * Parses the specified template file into a list of notification message
306       * template elements.
307       *
308       * @param  f  A reference to the template file to be parsed.
309       *
310       * @return  A list of notification message template elements parsed from the
311       *          specified file.
312       *
313       * @throws  ConfigException  If error occurs while attempting to parse the
314       *                           template file.
315       */
316      private List<NotificationMessageTemplateElement> parseTemplateFile(File f)
317              throws ConfigException
318      {
319        LinkedList<NotificationMessageTemplateElement> elementList =
320             new LinkedList<NotificationMessageTemplateElement>();
321    
322        BufferedReader reader = null;
323        try
324        {
325          reader = new BufferedReader(new FileReader(f));
326          int lineNumber = 0;
327          while (true)
328          {
329            String line = reader.readLine();
330            if (line == null)
331            {
332              break;
333            }
334    
335            if (debugEnabled())
336            {
337              TRACER.debugInfo("Read message template line " + line);
338            }
339    
340            lineNumber++;
341            int startPos = 0;
342            while (startPos < line.length())
343            {
344              int delimPos = line.indexOf("%%", startPos);
345              if (delimPos < 0)
346              {
347                if (debugEnabled())
348                {
349                  TRACER.debugInfo("No more tokens -- adding text " +
350                                   line.substring(startPos));
351                }
352    
353                elementList.add(new TextNotificationMessageTemplateElement(
354                                         line.substring(startPos)));
355                break;
356              }
357              else
358              {
359                if (delimPos > startPos)
360                {
361                  if (debugEnabled())
362                  {
363                    TRACER.debugInfo("Adding text before token " +
364                                     line.substring(startPos));
365                  }
366    
367                  elementList.add(new TextNotificationMessageTemplateElement(
368                                           line.substring(startPos, delimPos)));
369                }
370    
371                int closeDelimPos = line.indexOf("%%", delimPos+1);
372                if (closeDelimPos < 0)
373                {
374                  // There was an opening %% but not a closing one.
375                  throw new ConfigException(
376                                 ERR_SMTP_ASNH_TEMPLATE_UNCLOSED_TOKEN.get(
377                                      delimPos, lineNumber));
378                }
379                else
380                {
381                  String tokenStr = line.substring(delimPos+2, closeDelimPos);
382                  String lowerTokenStr = toLowerCase(tokenStr);
383                  if (lowerTokenStr.equals("notification-type"))
384                  {
385                    if (debugEnabled())
386                    {
387                      TRACER.debugInfo("Found a notification type token " +
388                                       tokenStr);
389                    }
390    
391                    elementList.add(
392                         new NotificationTypeNotificationMessageTemplateElement());
393                  }
394                  else if (lowerTokenStr.equals("notification-message"))
395                  {
396                    if (debugEnabled())
397                    {
398                      TRACER.debugInfo("Found a notification message token " +
399                                       tokenStr);
400                    }
401    
402                    elementList.add(
403                      new NotificationMessageNotificationMessageTemplateElement());
404                  }
405                  else if (lowerTokenStr.equals("notification-user-dn"))
406                  {
407                    if (debugEnabled())
408                    {
409                      TRACER.debugInfo("Found a notification user DN token " +
410                                       tokenStr);
411                    }
412    
413                    elementList.add(
414                         new UserDNNotificationMessageTemplateElement());
415                  }
416                  else if (lowerTokenStr.startsWith("notification-user-attr:"))
417                  {
418                    String attrName = lowerTokenStr.substring(23);
419                    AttributeType attrType =
420                         DirectoryServer.getAttributeType(attrName, false);
421                    if (attrType == null)
422                    {
423                      throw new ConfigException(
424                                     ERR_SMTP_ASNH_TEMPLATE_UNDEFINED_ATTR_TYPE.get(
425                                          delimPos, lineNumber, attrName));
426                    }
427                    else
428                    {
429                      if (debugEnabled())
430                      {
431                        TRACER.debugInfo("Found a user attribute token for  " +
432                                         attrType.getNameOrOID() + " -- " +
433                                         tokenStr);
434                      }
435    
436                      elementList.add(
437                           new UserAttributeNotificationMessageTemplateElement(
438                                    attrType));
439                    }
440                  }
441                  else if (lowerTokenStr.startsWith("notification-property:"))
442                  {
443                    String propertyName = lowerTokenStr.substring(22);
444                    AccountStatusNotificationProperty property =
445                         AccountStatusNotificationProperty.forName(propertyName);
446                    if (property == null)
447                    {
448                      throw new ConfigException(
449                                     ERR_SMTP_ASNH_TEMPLATE_UNDEFINED_PROPERTY.get(
450                                          delimPos, lineNumber, propertyName));
451                    }
452                    else
453                    {
454                      if (debugEnabled())
455                      {
456                        TRACER.debugInfo("Found a notification property token " +
457                                         "for " + propertyName + " -- " + tokenStr);
458                      }
459    
460                      elementList.add(
461                        new NotificationPropertyNotificationMessageTemplateElement(
462                              property));
463                    }
464                  }
465                  else
466                  {
467                    throw new ConfigException(
468                                   ERR_SMTP_ASNH_TEMPLATE_UNRECOGNIZED_TOKEN.get(
469                                        tokenStr, delimPos, lineNumber));
470                  }
471    
472                  startPos = closeDelimPos + 2;
473                }
474              }
475            }
476    
477    
478            // We need to put a CRLF at the end of the line, as per the SMTP spec.
479            elementList.add(new TextNotificationMessageTemplateElement("\r\n"));
480          }
481    
482          return elementList;
483        }
484        catch (Exception e)
485        {
486          if (debugEnabled())
487          {
488            TRACER.debugCaught(DebugLogLevel.ERROR, e);
489          }
490    
491          throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_CANNOT_PARSE.get(
492                                         f.getAbsolutePath(),
493                                         currentConfig.dn().toString(),
494                                         getExceptionMessage(e)));
495        }
496        finally
497        {
498          try
499          {
500            if (reader != null)
501            {
502              reader.close();
503            }
504          } catch (Exception e) {}
505        }
506      }
507    
508    
509    
510      /**
511       * {@inheritDoc}
512       */
513      public boolean isConfigurationAcceptable(
514                          AccountStatusNotificationHandlerCfg
515                               configuration,
516                          List<Message> unacceptableReasons)
517      {
518        SMTPAccountStatusNotificationHandlerCfg config =
519             (SMTPAccountStatusNotificationHandlerCfg) configuration;
520        return isConfigurationChangeAcceptable(config, unacceptableReasons);
521      }
522    
523    
524    
525      /**
526       * {@inheritDoc}
527       */
528      public void handleStatusNotification(AccountStatusNotification notification)
529      {
530        SMTPAccountStatusNotificationHandlerCfg config = currentConfig;
531        HashMap<AccountStatusNotificationType,String> subjects = subjectMap;
532        HashMap<AccountStatusNotificationType,
533                List<NotificationMessageTemplateElement>> templates = templateMap;
534    
535    
536        // First, see if the notification type is one that we handle.  If not, then
537        // return without doing anything.
538        AccountStatusNotificationType notificationType =
539             notification.getNotificationType();
540        List<NotificationMessageTemplateElement> templateElements =
541             templates.get(notificationType);
542        if (templateElements == null)
543        {
544          if (debugEnabled())
545          {
546            TRACER.debugInfo("No message template for notification type " +
547                             notificationType.getName());
548          }
549    
550          return;
551        }
552    
553    
554        // It is a notification that should be handled, so we can start generating
555        // the e-mail message.  First, check to see if there are any mail attributes
556        // that would cause us to send a message to the end user.
557        LinkedList<String> recipients = new LinkedList<String>();
558        Set<AttributeType> addressAttrs = config.getEmailAddressAttributeType();
559        Set<String> recipientAddrs = config.getRecipientAddress();
560        if ((addressAttrs != null) && (! addressAttrs.isEmpty()))
561        {
562          Entry userEntry = notification.getUserEntry();
563          for (AttributeType t : addressAttrs)
564          {
565            List<Attribute> attrList = userEntry.getAttribute(t);
566            if (attrList != null)
567            {
568              for (Attribute a : attrList)
569              {
570                for (AttributeValue v : a.getValues())
571                {
572                  if (debugEnabled())
573                  {
574                    TRACER.debugInfo("Adding end user recipient " +
575                                     v.getStringValue() + " from attr " +
576                                     a.getNameWithOptions());
577                  }
578    
579                  recipients.add(v.getStringValue());
580                }
581              }
582            }
583          }
584    
585          if (recipients.isEmpty())
586          {
587            if ((recipientAddrs == null) || recipientAddrs.isEmpty())
588            {
589              // There are no recipients at all, so there's no point in generating
590              // the message.  Return without doing anything.
591              if (debugEnabled())
592              {
593                TRACER.debugInfo("No end user recipients, and no explicit " +
594                                 "recipients");
595              }
596    
597              return;
598            }
599            else
600            {
601              if (! config.isSendMessageWithoutEndUserAddress())
602              {
603                // We can't send the message to the end user, and the handler is
604                // configured to not send only to administrators, so we shouln't
605                // do anything.
606                if (debugEnabled())
607                {
608                  TRACER.debugInfo("No end user recipients, and shouldn't send " +
609                                   "without end user recipients");
610                }
611    
612                return;
613              }
614            }
615          }
616        }
617    
618    
619        // Next, add any explicitly-defined recipients.
620        if (recipientAddrs != null)
621        {
622          if (debugEnabled())
623          {
624            for (String s : recipientAddrs)
625            {
626              TRACER.debugInfo("Adding explicit recipient " + s);
627            }
628          }
629    
630          recipients.addAll(recipientAddrs);
631        }
632    
633    
634        // Get the message subject to use.  If none is defined, then use a generic
635        // subject.
636        String subject = subjects.get(notificationType);
637        if (subject == null)
638        {
639          subject = INFO_SMTP_ASNH_DEFAULT_SUBJECT.get().toString();
640    
641          if (debugEnabled())
642          {
643            TRACER.debugInfo("Using default subject of " + subject);
644          }
645        }
646        else if (debugEnabled())
647        {
648          TRACER.debugInfo("Using per-type subject of " + subject);
649        }
650    
651    
652    
653        // Generate the message body.
654        MessageBuilder messageBody = new MessageBuilder();
655        for (NotificationMessageTemplateElement e : templateElements)
656        {
657          e.generateValue(messageBody, notification);
658        }
659    
660    
661        // Create and send the e-mail message.
662        EMailMessage message = new EMailMessage(config.getSenderAddress(),
663                                                recipients, subject);
664        message.setBody(messageBody);
665        if (debugEnabled())
666        {
667          TRACER.debugInfo("Set message body of " + messageBody.toString());
668        }
669    
670    
671        try
672        {
673          message.send();
674    
675          if (debugEnabled())
676          {
677            TRACER.debugInfo("Successfully sent the message");
678          }
679        }
680        catch (Exception e)
681        {
682          if (debugEnabled())
683          {
684            TRACER.debugCaught(DebugLogLevel.ERROR, e);
685          }
686    
687          logError(ERR_SMTP_ASNH_CANNOT_SEND_MESSAGE.get(notificationType.getName(),
688                        notification.getUserDN().toString(),
689                        getExceptionMessage(e)));
690        }
691      }
692    
693    
694    
695      /**
696       * {@inheritDoc}
697       */
698      public boolean isConfigurationChangeAcceptable(
699                          SMTPAccountStatusNotificationHandlerCfg configuration,
700                          List<Message> unacceptableReasons)
701      {
702        boolean configAcceptable = true;
703    
704    
705        // Make sure that the Directory Server is configured with information about
706        // one or more mail servers.
707        List<Properties> propList = DirectoryServer.getMailServerPropertySets();
708        if ((propList == null) || propList.isEmpty())
709        {
710          unacceptableReasons.add(ERR_SMTP_ASNH_NO_MAIL_SERVERS_CONFIGURED.get(
711                                       configuration.dn().toString()));
712          configAcceptable = false;
713        }
714    
715    
716        // Make sure that either an explicit recipient list or a set of email
717        // address attributes were provided.
718        Set<AttributeType> mailAttrs = configuration.getEmailAddressAttributeType();
719        Set<String> recipients = configuration.getRecipientAddress();
720        if (((mailAttrs == null) || mailAttrs.isEmpty()) &&
721            ((recipients == null) || recipients.isEmpty()))
722        {
723          unacceptableReasons.add(ERR_SMTP_ASNH_NO_RECIPIENTS.get(
724                                       configuration.dn().toString()));
725          configAcceptable = false;
726        }
727    
728        try
729        {
730          parseSubjects(configuration);
731        }
732        catch (ConfigException ce)
733        {
734          if (debugEnabled())
735          {
736            TRACER.debugCaught(DebugLogLevel.ERROR, ce);
737          }
738    
739          unacceptableReasons.add(ce.getMessageObject());
740          configAcceptable = false;
741        }
742    
743        try
744        {
745          parseTemplates(configuration);
746        }
747        catch (ConfigException ce)
748        {
749          if (debugEnabled())
750          {
751            TRACER.debugCaught(DebugLogLevel.ERROR, ce);
752          }
753    
754          unacceptableReasons.add(ce.getMessageObject());
755          configAcceptable = false;
756        }
757    
758        return configAcceptable;
759      }
760    
761    
762    
763      /**
764       * {@inheritDoc}
765       */
766      public ConfigChangeResult applyConfigurationChange(
767                  SMTPAccountStatusNotificationHandlerCfg configuration)
768      {
769        try
770        {
771          HashMap<AccountStatusNotificationType,String> subjects =
772               parseSubjects(configuration);
773          HashMap<AccountStatusNotificationType,
774                  List<NotificationMessageTemplateElement>> templates =
775               parseTemplates(configuration);
776    
777          currentConfig = configuration;
778          subjectMap    = subjects;
779          templateMap   = templates;
780          return new ConfigChangeResult(ResultCode.SUCCESS, false);
781        }
782        catch (ConfigException ce)
783        {
784          if (debugEnabled())
785          {
786            TRACER.debugCaught(DebugLogLevel.ERROR, ce);
787          }
788    
789          LinkedList<Message> messageList = new LinkedList<Message>();
790          messageList.add(ce.getMessageObject());
791    
792          return new ConfigChangeResult(ResultCode.UNWILLING_TO_PERFORM, false,
793                                        messageList);
794        }
795      }
796    }
797