/**
  * Verify that injecting non existing exceptions is flagged with an exception.
  *
  * @throws Exception
  */
 public void testInjectingNonExistingComponent() throws Exception {
   Map<String, Object> attributes = Maps.newHashMap();
   Appendable out = new StringBuffer();
   Integration integration = service.createIntegration("", Mode.UTEST, true, null);
   try {
     integration.injectComponent("foo:bared", attributes, "", "", out);
     fail(
         "Instantiating component through integration service should have failed because of missing component def.");
   } catch (DefinitionNotFoundException expected) {
     // Expected exception
     assertTrue(expected.getMessage().contains("No COMPONENT named markup://foo:bared found"));
   }
 }
 /** Verify that only component defs can be injected. */
 public void testInjectingApplications() throws Exception {
   String validApp = "test:laxSecurity";
   Map<String, Object> attributes = Maps.newHashMap();
   Appendable out = new StringBuffer();
   Integration integration = service.createIntegration("", Mode.UTEST, true, null);
   try {
     integration.injectComponent(validApp, attributes, "", "", out);
     fail("Injecting an application through integration service should have failed.");
   } catch (DefinitionNotFoundException expected) {
     // TODO: Maybe a better error message?
     assertTrue(
         expected.getMessage().contains("No COMPONENT named markup://test:laxSecurity found"));
   }
 }
  /**
   * A private helper routine to make the compiler code more sane.
   *
   * <p>This processes a single definition in a dependency tree. It works as a single step in a
   * breadth first traversal of the tree, accumulating children in the 'deps' set, and updating the
   * compile context with the current definition.
   *
   * <p>Note that once the definition has been retrieved, this code uses the 'canonical' descriptor
   * from the definition, discarding the incoming descriptor.
   *
   * @param descriptor the descriptor that we are currently handling, must not be in the compiling
   *     defs.
   * @param cc the compile context to allow us to accumulate information.
   * @param deps the set of dependencies that we are accumulating.
   * @throws QuickFixException if the definition is not found, or validateDefinition() throws one.
   */
  private <D extends Definition> D getHelper(
      DefDescriptor<D> descriptor, CompileContext cc, Set<DefDescriptor<?>> deps)
      throws QuickFixException {
    CompilingDef<D> cd = cc.getCompiling(descriptor);

    if (cd.def != null) {
      return cd.def;
    }
    try {
      if (!fillCompilingDef(cd, cc.context)) {
        //
        // At this point, we have failed to get the def, so we should throw an
        // error. The first stanza is to provide a more useful error description
        // including the set of components using the missing component.
        //
        if (!cd.parents.isEmpty()) {
          StringBuilder sb = new StringBuilder();
          Location handy = null;
          for (Definition parent : cd.parents) {
            handy = parent.getLocation();
            if (sb.length() != 0) {
              sb.append(", ");
            }
            sb.append(parent.getDescriptor().toString());
          }
          throw new DefinitionNotFoundException(descriptor, handy, sb.toString());
        }
        throw new DefinitionNotFoundException(descriptor);
      }
      //
      // Ok. We have a def. let's figure out what to do with it.
      //
      Set<DefDescriptor<?>> newDeps = Sets.newHashSet();
      cd.def.appendDependencies(newDeps);
      //
      // FIXME: this code will go away with preloads.
      // This pulls in the context preloads. not pretty, but it works.
      //
      if (!cc.addedPreloads && cd.descriptor.getDefType().equals(DefType.APPLICATION)) {
        cc.addedPreloads = true;
        Set<String> preloads = cc.context.getPreloads();
        for (String preload : preloads) {
          if (!preload.contains("_")) {
            DependencyDefImpl.Builder ddb = new DependencyDefImpl.Builder();
            ddb.setResource(preload);
            ddb.setType("APPLICATION,COMPONENT,STYLE,EVENT");
            ddb.build().appendDependencies(newDeps);
          }
        }
      }
      for (DefDescriptor<?> dep : newDeps) {
        if (!defs.containsKey(dep)) {
          CompilingDef<?> depcd = cc.getCompiling(dep);
          depcd.parents.add(cd.def);
        }
      }
      deps.addAll(newDeps);
      cc.dependencies.put(cd.descriptor, cd.def);
      return cd.def;
    } catch (DefinitionNotFoundException dnfe) {
      //
      // In the case that we have a DefinitionNotFoundException for our current descriptor,
      // cache the fact that we didn't find one.
      //
      if (dnfe.getDescriptor().equals(descriptor)) {
        cd.def = null;
        defs.put(descriptor, cd.def);
        if (cd.cacheable) {
          defsCache.put(descriptor, Optional.fromNullable(cd.def));
        }
      }
      throw dnfe;
    }
  }
  /**
   * Handle an exception in the servlet.
   *
   * <p>This routine should be called whenever an exception has surfaced to the top level of the
   * servlet. It should not be overridden unless Aura is entirely subsumed. Most special cases can
   * be handled by the Aura user by implementing {@link ExceptionAdapter ExceptionAdapter}.
   *
   * @param t the throwable to write out.
   * @param quickfix is this exception a valid quick-fix
   * @param context the aura context.
   * @param request the request.
   * @param response the response.
   * @param written true if we have started writing to the output stream.
   * @throws IOException if the output stream does.
   * @throws ServletException if send404 does (should not generally happen).
   */
  @Override
  public void handleServletException(
      Throwable t,
      boolean quickfix,
      AuraContext context,
      HttpServletRequest request,
      HttpServletResponse response,
      boolean written)
      throws IOException {
    try {
      Throwable mappedEx = t;
      boolean map = !quickfix;
      Format format = context.getFormat();

      //
      // This seems to fail, though the documentation implies that you can do
      // it.
      //
      // if (written && !response.isCommitted()) {
      // response.resetBuffer();
      // written = false;
      // }
      if (!written) {
        // Should we only delete for JSON?
        setNoCache(response);
      }
      if (mappedEx instanceof IOException) {
        //
        // Just re-throw IOExceptions.
        //
        throw (IOException) mappedEx;
      } else if (mappedEx instanceof NoAccessException) {
        Throwable cause = mappedEx.getCause();
        String denyMessage = mappedEx.getMessage();

        map = false;
        if (cause != null) {
          //
          // Note that the exception handler can remap the cause here.
          //
          cause = exceptionAdapter.handleException(cause);
          denyMessage += ": cause = " + cause.getMessage();
        }
        //
        // Is this correct?!?!?!
        //
        if (format != Format.JSON) {
          this.send404(request.getServletContext(), request, response);
          if (!isProductionMode(context.getMode())) {
            // Preserve new lines and tabs in the stacktrace since this is directly being written on
            // to the
            // page
            denyMessage = "<pre>" + AuraTextUtil.escapeForHTML(denyMessage) + "</pre>";
            response.getWriter().println(denyMessage);
          }
          return;
        }
      } else if (mappedEx instanceof QuickFixException) {
        if (isProductionMode(context.getMode())) {
          //
          // In production environments, we want wrap the quick-fix. But be a little careful here.
          // We should never mark the top level as a quick-fix, because that means that we gack
          // on every mis-spelled app. In this case we simply send a 404 and bolt.
          //
          if (mappedEx instanceof DefinitionNotFoundException) {
            DefinitionNotFoundException dnfe = (DefinitionNotFoundException) mappedEx;

            if (dnfe.getDescriptor() != null
                && dnfe.getDescriptor().equals(context.getApplicationDescriptor())) {
              // We're in production and tried to hit an aura app that doesn't exist.
              // just show the standard 404 page.
              this.send404(request.getServletContext(), request, response);
              return;
            }
          }
          map = true;
          mappedEx = new AuraUnhandledException("404 Not Found (Application Error)", mappedEx);
        }
      }
      if (map) {
        mappedEx = exceptionAdapter.handleException(mappedEx);
      }

      PrintWriter out = response.getWriter();

      //
      // If we have written out data, We are kinda toast in this case.
      // We really want to roll it all back, but we can't, so we opt
      // for the best we can do. For HTML we can do nothing at all.
      //
      if (format == Format.JSON) {
        if (!written) {
          out.write(CSRF_PROTECT);
        }
        //
        // If an exception happened while we were emitting JSON, we want the
        // client to ignore the now-corrupt data structure. 404s and 500s
        // cause the client to prepend /*, so we can effectively erase the
        // bad data by appending a */ here and then serializing the exception
        // info.
        //
        out.write("*/");
        //
        // Unfortunately we can't do the following now. It might be possible
        // in some cases, but we don't want to go there unless we have to.
        //
      }
      if (format == Format.JS || format == Format.CSS) {
        // Make sure js and css doesn't get cached in browser, appcache, etc
        response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
      }
      if (format == Format.JSON
          || format == Format.HTML
          || format == Format.JS
          || format == Format.CSS) {
        //
        // We only write out exceptions for HTML or JSON.
        // Seems bogus, but here it is.
        //
        // Start out by cleaning out some settings to ensure we don't
        // check too many things, leading to a circular failure. Note
        // that this is still a bit dangerous, as we seem to have a lot
        // of magic in the serializer.
        //
        // Clear the InstanceStack before trying to serialize the exception since the Throwable has
        // likely
        // rendered the stack inaccurate, and may falsely trigger NoAccessExceptions.
        InstanceStack stack = this.contextService.getCurrentContext().getInstanceStack();
        List<String> list = stack.getStackInfo();
        for (int count = list.size(); count > 0; count--) {
          stack.popInstance(stack.peek());
        }

        serializationService.write(mappedEx, null, out);
        if (format == Format.JSON) {
          out.write("/*ERROR*/");
        }
      }
    } catch (IOException ioe) {
      throw ioe;
    } catch (Throwable death) {
      //
      // Catch any other exception and log it. This is actually kinda bad, because something has
      // gone horribly wrong. We should write out some sort of generic page other than a 404,
      // but at this point, it is unclear what we can do, as stuff is breaking right and left.
      //
      try {
        response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
        exceptionAdapter.handleException(death);
        if (!isProductionMode(context.getMode())) {
          response.getWriter().println(death.getMessage());
        }
      } catch (IOException ioe) {
        throw ioe;
      } catch (Throwable doubleDeath) {
        // we are totally hosed.
        if (!isProductionMode(context.getMode())) {
          response.getWriter().println(doubleDeath.getMessage());
        }
      }
    } finally {
      this.contextService.endContext();
    }
  }