1 /*
   2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import java.text.MessageFormat;
  29 import java.util.Locale;
  30 import java.util.ResourceBundle;
  31 import jdk.nashorn.api.scripting.NashornException;
  32 import jdk.nashorn.internal.scripts.JS;
  33 import jdk.nashorn.internal.codegen.CompilerConstants;
  34 
  35 /**
  36  * Helper class to throw various standard "ECMA error" exceptions such as Error, ReferenceError, TypeError etc.
  37  */
  38 public final class ECMAErrors {
  39     private static final String MESSAGES_RESOURCE = "jdk.nashorn.internal.runtime.resources.Messages";
  40 
  41     private static final ResourceBundle MESSAGES_BUNDLE;
  42     static {
  43         MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault());
  44     }
  45 
  46     /** We assume that compiler generates script classes into the known package. */
  47     private static final String scriptPackage;
  48     static {
  49         String name = JS.class.getName();
  50         scriptPackage = name.substring(0, name.lastIndexOf('.'));
  51     }
  52 
  53     private ECMAErrors() {
  54     }
  55 
  56     private static ECMAException error(final Object thrown, final Throwable cause) {
  57         return new ECMAException(thrown, cause);
  58     }
  59 
  60      /**
  61      * Error dispatch mechanism.
  62      * Create a {@link ParserException} as the correct JavaScript error
  63      *
  64      * @param e {@code ParserException} for error dispatcher
  65      *
  66      * @return the resulting {@link ECMAException}
  67      */
  68     public static ECMAException asEcmaException(final ParserException e) {
  69         return asEcmaException(Context.getGlobalTrusted(), e);
  70     }
  71 
  72     /**
  73      * Error dispatch mechanism.
  74      * Create a {@link ParserException} as the correct JavaScript error
  75      *
  76      * @param global global scope object
  77      * @param e {@code ParserException} for error dispatcher
  78      *
  79      * @return the resulting {@link ECMAException}
  80      */
  81     public static ECMAException asEcmaException(final ScriptObject global, final ParserException e) {
  82         final JSErrorType errorType = e.getErrorType();
  83         assert errorType != null : "error type for " + e + " was null";
  84 
  85         final GlobalObject globalObj = (GlobalObject)global;
  86         final String       msg    = e.getMessage();
  87 
  88         // translate to ECMAScript Error object using error type
  89         switch (errorType) {
  90         case ERROR:
  91             return error(globalObj.newError(msg), e);
  92         case EVAL_ERROR:
  93             return error(globalObj.newEvalError(msg), e);
  94         case RANGE_ERROR:
  95             return error(globalObj.newRangeError(msg), e);
  96         case REFERENCE_ERROR:
  97             return error(globalObj.newReferenceError(msg), e);
  98         case SYNTAX_ERROR:
  99             return error(globalObj.newSyntaxError(msg), e);
 100         case TYPE_ERROR:
 101             return error(globalObj.newTypeError(msg), e);
 102         case URI_ERROR:
 103             return error(globalObj.newURIError(msg), e);
 104         default:
 105             // should not happen - perhaps unknown error type?
 106             throw new AssertionError(e.getMessage());
 107         }
 108     }
 109 
 110     /**
 111      * Create a syntax error (ECMA 15.11.6.4)
 112      *
 113      * @param msgId   resource tag for error message
 114      * @param args    arguments to resource
 115      *
 116      * @return the resulting {@link ECMAException}
 117      */
 118     public static ECMAException syntaxError(final String msgId, final String... args) {
 119         return syntaxError(Context.getGlobalTrusted(), msgId, args);
 120     }
 121 
 122     /**
 123      * Create a syntax error (ECMA 15.11.6.4)
 124      *
 125      * @param global  global scope object
 126      * @param msgId   resource tag for error message
 127      * @param args    arguments to resource
 128      *
 129      * @return the resulting {@link ECMAException}
 130      */
 131     public static ECMAException syntaxError(final ScriptObject global, final String msgId, final String... args) {
 132         return syntaxError(global, null, msgId, args);
 133     }
 134 
 135     /**
 136      * Create a syntax error (ECMA 15.11.6.4)
 137      *
 138      * @param cause   native Java {@code Throwable} that is the cause of error
 139      * @param msgId   resource tag for error message
 140      * @param args    arguments to resource
 141      *
 142      * @return the resulting {@link ECMAException}
 143      */
 144     public static ECMAException syntaxError(final Throwable cause, final String msgId, final String... args) {
 145         return syntaxError(Context.getGlobalTrusted(), cause, msgId, args);
 146     }
 147 
 148     /**
 149      * Create a syntax error (ECMA 15.11.6.4)
 150      *
 151      * @param global  global scope object
 152      * @param cause   native Java {@code Throwable} that is the cause of error
 153      * @param msgId   resource tag for error message
 154      * @param args    arguments to resource
 155      *
 156      * @return the resulting {@link ECMAException}
 157      */
 158     public static ECMAException syntaxError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
 159         final String msg = getMessage("syntax.error." + msgId, args);
 160         return error(((GlobalObject)global).newSyntaxError(msg), cause);
 161     }
 162 
 163     /**
 164      * Create a type error (ECMA 15.11.6.5)
 165      *
 166      * @param msgId   resource tag for error message
 167      * @param args    arguments to resource
 168      *
 169      * @return the resulting {@link ECMAException}
 170      */
 171     public static ECMAException typeError(final String msgId, final String... args) {
 172         return typeError(Context.getGlobalTrusted(), msgId, args);
 173     }
 174 
 175     /**
 176      * Create a type error (ECMA 15.11.6.5)
 177      *
 178      * @param global  global scope object
 179      * @param msgId   resource tag for error message
 180      * @param args    arguments to resource
 181      *
 182      * @return the resulting {@link ECMAException}
 183      */
 184     public static ECMAException typeError(final ScriptObject global, final String msgId, final String... args) {
 185         return typeError(global, null, msgId, args);
 186     }
 187 
 188     /**
 189      * Create a type error (ECMA 15.11.6.5)
 190      *
 191      * @param cause   native Java {@code Throwable} that is the cause of error
 192      * @param msgId   resource tag for error message
 193      * @param args    arguments to resource
 194      *
 195      * @return the resulting {@link ECMAException}
 196      */
 197     public static ECMAException typeError(final Throwable cause, final String msgId, final String... args) {
 198         return typeError(Context.getGlobalTrusted(), cause, msgId, args);
 199     }
 200 
 201     /**
 202      * Create a type error (ECMA 15.11.6.5)
 203      *
 204      * @param global  global scope object
 205      * @param cause   native Java {@code Throwable} that is the cause of error
 206      * @param msgId   resource tag for error message
 207      * @param args    arguments to resource
 208      *
 209      * @return the resulting {@link ECMAException}
 210      */
 211     public static ECMAException typeError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
 212         final String msg = getMessage("type.error." + msgId, args);
 213         return error(((GlobalObject)global).newTypeError(msg), cause);
 214     }
 215 
 216     /**
 217      * Create a range error (ECMA 15.11.6.2)
 218      *
 219      * @param msgId   resource tag for error message
 220      * @param args    arguments to resource
 221      *
 222      * @return the resulting {@link ECMAException}
 223      */
 224     public static ECMAException rangeError(final String msgId, final String... args) {
 225         return rangeError(Context.getGlobalTrusted(), msgId, args);
 226     }
 227 
 228     /**
 229      * Create a range error (ECMA 15.11.6.2)
 230      *
 231      * @param global  global scope object
 232      * @param msgId   resource tag for error message
 233      * @param args    arguments to resource
 234      *
 235      * @return the resulting {@link ECMAException}
 236      */
 237     public static ECMAException rangeError(final ScriptObject global, final String msgId, final String... args) {
 238         return rangeError(global, null, msgId, args);
 239     }
 240 
 241     /**
 242      * Create a range error (ECMA 15.11.6.2)
 243      *
 244      * @param cause   native Java {@code Throwable} that is the cause of error
 245      * @param msgId   resource tag for error message
 246      * @param args    arguments to resource
 247      *
 248      * @return the resulting {@link ECMAException}
 249      */
 250     public static ECMAException rangeError(final Throwable cause, final String msgId, final String... args) {
 251         return rangeError(Context.getGlobalTrusted(), cause, msgId, args);
 252     }
 253 
 254     /**
 255      * Create a range error (ECMA 15.11.6.2)
 256      *
 257      * @param global  global scope object
 258      * @param cause   native Java {@code Throwable} that is the cause of error
 259      * @param msgId   resource tag for error message
 260      * @param args    arguments to resource
 261      *
 262      * @return the resulting {@link ECMAException}
 263      */
 264     public static ECMAException rangeError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
 265         final String msg = getMessage("range.error." + msgId, args);
 266         return error(((GlobalObject)global).newRangeError(msg), cause);
 267     }
 268 
 269     /**
 270      * Create a reference error (ECMA 15.11.6.3)
 271      *
 272      * @param msgId   resource tag for error message
 273      * @param args    arguments to resource
 274      *
 275      * @return the resulting {@link ECMAException}
 276      */
 277     public static ECMAException referenceError(final String msgId, final String... args) {
 278         return referenceError(Context.getGlobalTrusted(), msgId, args);
 279     }
 280 
 281     /**
 282      * Create a reference error (ECMA 15.11.6.3)
 283      *
 284      * @param global  global scope object
 285      * @param msgId   resource tag for error message
 286      * @param args    arguments to resource
 287      *
 288      * @return the resulting {@link ECMAException}
 289      */
 290     public static ECMAException referenceError(final ScriptObject global, final String msgId, final String... args) {
 291         return referenceError(global, null, msgId, args);
 292     }
 293 
 294     /**
 295      * Create a reference error (ECMA 15.11.6.3)
 296      *
 297      * @param cause   native Java {@code Throwable} that is the cause of error
 298      * @param msgId   resource tag for error message
 299      * @param args    arguments to resource
 300      *
 301      * @return the resulting {@link ECMAException}
 302      */
 303     public static ECMAException referenceError(final Throwable cause, final String msgId, final String... args) {
 304         return referenceError(Context.getGlobalTrusted(), cause, msgId, args);
 305     }
 306 
 307     /**
 308      * Create a reference error (ECMA 15.11.6.3)
 309      *
 310      * @param global  global scope object
 311      * @param cause   native Java {@code Throwable} that is the cause of error
 312      * @param msgId   resource tag for error message
 313      * @param args    arguments to resource
 314      *
 315      * @return the resulting {@link ECMAException}
 316      */
 317     public static ECMAException referenceError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
 318         final String msg = getMessage("reference.error." + msgId, args);
 319         return error(((GlobalObject)global).newReferenceError(msg), cause);
 320     }
 321 
 322     /**
 323      * Create a URI error (ECMA 15.11.6.6)
 324      *
 325      * @param msgId   resource tag for error message
 326      * @param args    arguments to resource
 327      *
 328      * @return the resulting {@link ECMAException}
 329      */
 330     public static ECMAException uriError(final String msgId, final String... args) {
 331         return uriError(Context.getGlobalTrusted(), msgId, args);
 332     }
 333 
 334     /**
 335      * Create a URI error (ECMA 15.11.6.6)
 336      *
 337      * @param global  global scope object
 338      * @param msgId   resource tag for error message
 339      * @param args    arguments to resource
 340      *
 341      * @return the resulting {@link ECMAException}
 342      */
 343     public static ECMAException uriError(final ScriptObject global, final String msgId, final String... args) {
 344         return uriError(global, null, msgId, args);
 345     }
 346 
 347     /**
 348      * Create a URI error (ECMA 15.11.6.6)
 349      *
 350      * @param cause   native Java {@code Throwable} that is the cause of error
 351      * @param msgId   resource tag for error message
 352      * @param args    arguments to resource
 353      *
 354      * @return the resulting {@link ECMAException}
 355      */
 356     public static ECMAException uriError(final Throwable cause, final String msgId, final String... args) {
 357         return uriError(Context.getGlobalTrusted(), cause, msgId, args);
 358     }
 359 
 360     /**
 361      * Create a URI error (ECMA 15.11.6.6)
 362      *
 363      * @param global  global scope object
 364      * @param cause   native Java {@code Throwable} that is the cause of error
 365      * @param msgId   resource tag for error message
 366      * @param args    arguments to resource
 367      *
 368      * @return the resulting {@link ECMAException}
 369      */
 370     public static ECMAException uriError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
 371         final String msg = getMessage("uri.error." + msgId, args);
 372         return error(((GlobalObject)global).newURIError(msg), cause);
 373     }
 374 
 375     /**
 376      * Get the exception message by placing the args in the resource defined
 377      * by the resource tag. This is visible to, e.g. the {@link jdk.nashorn.internal.parser.Parser}
 378      * can use it to generate compile time messages with the correct locale
 379      *
 380      * @param msgId the resource tag (message id)
 381      * @param args  arguments to error string
 382      *
 383      * @return the filled out error string
 384      */
 385     public static String getMessage(final String msgId, final String... args) {
 386         try {
 387             return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args);
 388         } catch (final java.util.MissingResourceException e) {
 389             throw new RuntimeException("no message resource found for message id: "+ msgId);
 390         }
 391     }
 392 
 393 
 394     /**
 395      * Check if a stack trace element is in JavaScript
 396      *
 397      * @param frame frame
 398      *
 399      * @return true if frame is in the script
 400      */
 401     public static boolean isScriptFrame(final StackTraceElement frame) {
 402         final String className = frame.getClassName();
 403 
 404         // Look for script package in class name (into which compiler puts generated code)
 405         if (className.startsWith(scriptPackage) && !frame.getMethodName().startsWith(CompilerConstants.INTERNAL_METHOD_PREFIX)) {
 406             final String source = frame.getFileName();
 407             /*
 408              * Make sure that it is not some Java code that Nashorn has in that package!
 409              * also, we don't want to report JavaScript code that lives in script engine implementation
 410              * We want to report only user's own scripts and not any of our own scripts like "engine.js"
 411              */
 412             return source != null && !source.endsWith(".java") && !source.contains(NashornException.ENGINE_SCRIPT_SOURCE_NAME);
 413         }
 414         return false;
 415     }
 416 }