View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.scxml2.env;
18  
19  import java.io.Serializable;
20  import java.util.Iterator;
21  import java.util.Map;
22  import java.util.Set;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.commons.scxml2.ErrorReporter;
27  import org.apache.commons.scxml2.model.Data;
28  import org.apache.commons.scxml2.model.EnterableState;
29  import org.apache.commons.scxml2.model.Executable;
30  import org.apache.commons.scxml2.model.SCXML;
31  import org.apache.commons.scxml2.model.State;
32  import org.apache.commons.scxml2.model.TransitionTarget;
33  import org.apache.commons.scxml2.semantics.ErrorConstants;
34  
35  /**
36   * Custom error reporter that log execution errors.
37   */
38  public class SimpleErrorReporter implements ErrorReporter, Serializable {
39  
40      /** Serial version UID. */
41      private static final long serialVersionUID = 1L;
42      /** Log. */
43      private Log log = LogFactory.getLog(getClass());
44  
45      /**
46       * Constructor.
47       */
48      public SimpleErrorReporter() {
49          super();
50      }
51  
52      /**
53       * @see ErrorReporter#onError(String, String, Object)
54       */
55      @SuppressWarnings("unchecked")
56      public void onError(final String errorCode, final String errDetail,
57              final Object errCtx) {
58          //Note: the if-then-else below is based on the actual usage
59          // (codebase search), it has to be kept up-to-date as the code changes
60          String errCode = errorCode.intern();
61          StringBuffer msg = new StringBuffer();
62          msg.append(errCode).append(" (");
63          msg.append(errDetail).append("): ");
64          if (errCode == ErrorConstants.NO_INITIAL) {
65              if (errCtx instanceof SCXML) {
66                  //determineInitialStates
67                  msg.append("<SCXML>");
68              } else if (errCtx instanceof State) {
69                  //determineInitialStates
70                  //determineTargetStates
71                  msg.append("State " + LogUtils.getTTPath((State) errCtx));
72              }
73          } else if (errCode == ErrorConstants.UNKNOWN_ACTION) {
74              //executeActionList
75              msg.append("Action: " + errCtx.getClass().getName());
76          } else if (errCode == ErrorConstants.ILLEGAL_CONFIG) {
77              //isLegalConfig
78              if (errCtx instanceof Map.Entry) { //unchecked cast below
79                  Map.Entry<EnterableState, Set<EnterableState>> badConfigMap =
80                      (Map.Entry<EnterableState, Set<EnterableState>>) errCtx;
81                  EnterableState es = badConfigMap.getKey();
82                  Set<EnterableState> vals = badConfigMap.getValue();
83                  msg.append(LogUtils.getTTPath(es) + " : [");
84                  for (Iterator<EnterableState> i = vals.iterator(); i.hasNext();) {
85                      EnterableState ex = i.next();
86                      msg.append(LogUtils.getTTPath(ex));
87                      if (i.hasNext()) { // reason for iterator usage
88                          msg.append(", ");
89                      }
90                  }
91                  msg.append(']');
92              } else if (errCtx instanceof Set) { //unchecked cast below
93                  Set<EnterableState> vals = (Set<EnterableState>) errCtx;
94                  msg.append("<SCXML> : [");
95                  for (Iterator<EnterableState> i = vals.iterator(); i.hasNext();) {
96                      EnterableState ex = i.next();
97                      msg.append(LogUtils.getTTPath(ex));
98                      if (i.hasNext()) {
99                          msg.append(", ");
100                     }
101                 }
102                 msg.append(']');
103             }
104         } else if (errCode == ErrorConstants.EXPRESSION_ERROR) {
105             if (errCtx instanceof Executable) {
106                 TransitionTarget parent = ((Executable) errCtx).getParent();
107                 msg.append("Expression error inside " + LogUtils.getTTPath(parent));
108             }
109             else if (errCtx instanceof Data) {
110                 // Data expression error
111                 msg.append("Expression error for data element with id "+((Data)errCtx).getId());
112             }
113             else if (errCtx instanceof SCXML) {
114                 // Global Script
115                 msg.append("Expression error inside the global script");
116             }
117         }
118         handleErrorMessage(errorCode, errDetail, errCtx, msg);
119     }
120 
121     /**
122      * Final handling of the resulting errorMessage build by {@link #onError(String, String, Object)} onError}.
123      * <p>The default implementation write the errorMessage as a warning to the log.</p>
124      */
125     protected void handleErrorMessage(final String errorCode, final String errDetail,
126                                final Object errCtx, final CharSequence errorMessage) {
127 
128         if (log.isWarnEnabled()) {
129             log.warn(errorMessage.toString());
130         }
131     }
132 }
133