private void addContributeeActionsIfAny(
      final ObjectAdapter serviceAdapter, final List<ObjectAction> contributeeActionsToAppendTo) {
    final ObjectSpecification specification = serviceAdapter.getSpecification();
    if (specification == this) {
      return;
    }
    final List<ObjectAction> contributeeActions = Lists.newArrayList();
    final List<ObjectAction> serviceActions =
        specification.getObjectActions(
            ActionType.ALL, Contributed.INCLUDED, Filters.<ObjectAction>any());
    for (final ObjectAction serviceAction : serviceActions) {
      if (isAlwaysHidden(serviceAction)) {
        continue;
      }
      final NotContributedFacet notContributed = serviceAction.getFacet(NotContributedFacet.class);
      if (notContributed != null && notContributed.toActions()) {
        continue;
      }
      if (!(serviceAction instanceof ObjectActionImpl)) {
        continue;
      }
      final ObjectActionImpl contributedAction = (ObjectActionImpl) serviceAction;

      // see if qualifies by inspecting all parameters
      final int contributeeParam = contributeeParameterMatchOf(contributedAction);
      if (contributeeParam != -1) {
        ObjectActionContributee contributeeAction =
            new ObjectActionContributee(
                serviceAdapter, contributedAction, contributeeParam, this, objectMemberContext);
        facetProcessor.processMemberOrder(metadataProperties, contributeeAction);
        contributeeActions.add(contributeeAction);
      }
    }
    contributeeActionsToAppendTo.addAll(contributeeActions);
  }
 private ObjectAction getAction(
     final List<ObjectAction> availableActions, final ActionType type, final String id) {
   if (id == null) {
     return null;
   }
   outer:
   for (int i = 0; i < availableActions.size(); i++) {
     final ObjectAction action = availableActions.get(i);
     if (action.getActions().size() > 0) {
       // deal with action set
       final ObjectAction a = getAction(action.getActions(), type, id);
       if (a != null) {
         return a;
       }
     } else {
       // regular action
       if (!type.matchesTypeOf(action)) {
         continue outer;
       }
       if (id.equals(action.getIdentifier().toNameParmsIdentityString())) {
         return action;
       }
       if (id.equals(action.getIdentifier().toNameIdentityString())) {
         return action;
       }
       continue outer;
     }
   }
   return null;
 }
  protected Object homePageIfUsable(ObjectAdapter serviceAdapter, ObjectAction objectAction) {
    if (!objectAction.containsDoOpFacet(HomePageFacet.class)) {
      return null;
    }

    final Consent visibility =
        objectAction.isVisible(serviceAdapter, InteractionInitiatedBy.USER, Where.ANYWHERE);
    if (visibility.isVetoed()) {
      return null;
    }

    final Consent usability =
        objectAction.isUsable(serviceAdapter, InteractionInitiatedBy.USER, Where.ANYWHERE);
    if (usability.isVetoed()) {
      return null;
    }

    final ObjectAdapter mixedInAdapter = null;
    final ObjectAdapter[] parameters = {};

    final ObjectAdapter objectAdapter =
        objectAction.executeWithRuleChecking(
            serviceAdapter,
            mixedInAdapter,
            parameters,
            InteractionInitiatedBy.USER,
            WHERE_FOR_ACTION_INVOCATION);

    return objectAdapter != null ? objectAdapter.getObject() : null;
  }
 private ObjectAction findAction(final ObjectSpecification specification, final String actionId) {
   final List<ObjectAction> objectActions = specification.getObjectActions(Contributed.INCLUDED);
   for (final ObjectAction objectAction : objectActions) {
     if (objectAction.getIdentifier().toClassAndNameIdentityString().equals(actionId)) {
       return objectAction;
     }
   }
   return null;
 }
  /**
   * Either creates a link for the action be rendered in a {@link ModalWindow}, or (if none can be
   * {@link ActionPromptProvider#getActionPrompt() provided}, or creates a link to the {@link
   * ActionPromptPage} (ie the {@link PageClassRegistry registered page} for {@link
   * PageType#ACTION_PROMPT action}s).
   *
   * <p>If the action's {@link ObjectAction#getSemantics() semantics} are {@link
   * ActionSemantics.Of#SAFE safe}, then concurrency checking is disabled; otherwise it is enforced.
   */
  protected AbstractLink newLink(
      final String linkId,
      final ObjectAdapter objectAdapter,
      final ObjectAction action,
      final ActionPromptProvider actionPromptProvider) {

    final ActionPrompt actionPrompt = actionPromptProvider.getActionPrompt();
    if (actionPrompt != null) {
      final ActionModel actionModel = ActionModel.create(objectAdapter, action);
      actionModel.setActionPrompt(actionPrompt);
      AjaxLink<Object> link =
          new AjaxLink<Object>(linkId) {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {

              final ActionPanel actionPromptPanel =
                  (ActionPanel)
                      getComponentFactoryRegistry()
                          .createComponent(
                              ComponentType.ACTION_PROMPT,
                              actionPrompt.getContentId(),
                              actionModel);

              actionPrompt.setPanel(actionPromptPanel, target);
              actionPrompt.show(target);

              target.focusComponent(actionPromptPanel);
            }
          };
      link.add(new CssClassAppender("noVeil"));
      return link;

    } else {

      // use the action semantics to determine whether invoking this action will require a
      // concurrency check or not
      // if it's "safe", then we'll just continue without any checking.
      final ConcurrencyChecking concurrencyChecking =
          ConcurrencyChecking.concurrencyCheckingFor(action.getSemantics());
      final PageParameters pageParameters =
          ActionModel.createPageParameters(objectAdapter, action, concurrencyChecking);
      final Class<? extends Page> pageClass =
          getPageClassRegistry().getPageClass(PageType.ACTION_PROMPT);
      AbstractLink link = Links.newBookmarkablePageLink(linkId, pageParameters, pageClass);

      // special case handling if this a no-arg action is returning a URL
      if (action.getParameterCount() == 0) {
        addTargetBlankIfActionReturnsUrl(link, action);
      }

      return link;
    }
  }
示例#6
0
  Property actionReturnTypeFor(final ObjectAction objectAction) {

    final ObjectSpecification specification = objectAction.getReturnType();
    TypeOfFacet typeOfFacet = objectAction.getFacet(TypeOfFacet.class);
    if (typeOfFacet != null) {
      ObjectSpecification elementSpec = typeOfFacet.valueSpec();
      if (elementSpec != null) {
        return arrayPropertyOf(elementSpec);
      }
    }
    return modelFor(specification);
  }
 private void catalogueActions(final Map<Method, ObjectMember> membersByMethod) {
   final List<ObjectAction> userActions = getObjectActions(ActionType.USER, Contributed.INCLUDED);
   for (int i = 0; i < userActions.size(); i++) {
     final ObjectAction userAction = userActions.get(i);
     final List<Facet> facets = userAction.getFacets(ImperativeFacet.FILTER);
     for (final Facet facet : facets) {
       final ImperativeFacet imperativeFacet = ImperativeFacetUtils.getImperativeFacet(facet);
       for (final Method imperativeFacetMethod : imperativeFacet.getMethods()) {
         membersByMethod.put(imperativeFacetMethod, userAction);
       }
     }
   }
 }
示例#8
0
  private Response invokeActionUsingAdapters(
      final ObjectAction action,
      final JsonRepresentation arguments,
      final ActionResultReprRenderer.SelfLink selfLink) {

    final RepresentationService.Context rendererContext = representationServiceContext;
    final ObjectAdapter objectAdapter = this.objectAdapter;

    final ObjectActionArgHelper argHelper =
        new ObjectActionArgHelper(rendererContext, objectAdapter, action);

    final List<ObjectAdapter> argAdapters = argHelper.parseAndValidateArguments(arguments);

    // invoke
    final ObjectAdapter mixedInAdapter = null; // action will automatically fill in if a mixin
    final ObjectAdapter[] argAdapterArr =
        argAdapters.toArray(new ObjectAdapter[argAdapters.size()]);
    final ObjectAdapter returnedAdapter =
        action.execute(objectAdapter, mixedInAdapter, argAdapterArr, InteractionInitiatedBy.USER);

    final ObjectAndActionInvocation objectAndActionInvocation =
        new ObjectAndActionInvocation(objectAdapter, action, arguments, returnedAdapter, selfLink);

    // response
    transactionService.flushTransaction();
    return representationService.actionResult(
        representationServiceContext, objectAndActionInvocation, selfLink);
  }
 private void addIfReturnsSubtype(
     final ObjectAction serviceAction, final List<ObjectAction> matchingActionsToAppendTo) {
   final ObjectSpecification returnType = serviceAction.getReturnType();
   if (returnType == null) {
     return;
   }
   if (returnType.isParentedOrFreeCollection()) {
     final TypeOfFacet facet = serviceAction.getFacet(TypeOfFacet.class);
     if (facet != null) {
       final ObjectSpecification elementType = facet.valueSpec();
       addIfReturnsSubtype(serviceAction, elementType, matchingActionsToAppendTo);
     }
   } else {
     addIfReturnsSubtype(serviceAction, returnType, matchingActionsToAppendTo);
   }
 }
 public static void addTargetBlankIfActionReturnsUrl(
     final AbstractLink link, final ObjectAction action) {
   final ObjectSpecification returnType = action.getReturnType();
   if (returnType != null && "java.net.URL".equals(returnType.getFullIdentifier())) {
     link.add(new AttributeAppender("target", Model.of("_blank")));
     link.add(new CssClassAppender("noVeil"));
   }
 }
示例#11
0
  private void processElement(
      final Request request, final FormFieldBlock block, final String field) {
    final String type = request.getOptionalProperty(TYPE, "dropdown");
    if (!request.isPropertySpecified(METHOD) && request.isPropertySpecified(COLLECTION)) {
      final String id = request.getRequiredProperty(COLLECTION, Request.NO_VARIABLE_CHECKING);
      final String selector =
          showSelectionList(request, id, block.getCurrent(field), block.isNullable(field), type);
      block.replaceContent(field, selector);
    } else {
      final String objectId = request.getOptionalProperty(OBJECT);
      final String methodName = request.getRequiredProperty(METHOD);
      final ObjectAdapter object = MethodsUtils.findObject(request.getContext(), objectId);
      final ObjectAction action = MethodsUtils.findAction(object, methodName);
      if (action.getParameterCount() == 0) {
        final ObjectAdapter collection = action.execute(object, new ObjectAdapter[0]);
        final String selector =
            showSelectionList(
                request, collection, block.getCurrent(field), block.isNullable(field), type);
        block.replaceContent(field, selector);
      } else {
        final String id = "selector_options";
        final String id2 = (String) request.getContext().getVariable(id);
        final String selector =
            showSelectionList(request, id2, block.getCurrent(field), block.isNullable(field), type);

        final CreateFormParameter parameters = new CreateFormParameter();
        parameters.objectId = objectId;
        parameters.methodName = methodName;
        parameters.buttonTitle = request.getOptionalProperty(BUTTON_TITLE, "Search");
        parameters.formTitle = request.getOptionalProperty(FORM_TITLE);
        parameters.className = request.getOptionalProperty(CLASS, "selector");
        parameters.id = request.getOptionalProperty(ID);

        parameters.resultName = id;
        parameters.forwardResultTo = request.getContext().getResourceFile();
        parameters.forwardVoidTo = "error";
        parameters.forwardErrorTo = parameters.forwardResultTo;
        parameters.scope = Scope.REQUEST.name();
        request.pushNewBuffer();
        ActionForm.createForm(request, parameters);
        block.replaceContent(field, selector);

        request.appendHtml(request.popBuffer());
      }
    }
  }
 private ObjectAction getAction(
     final List<ObjectAction> availableActions,
     final ActionType type,
     final String actionName,
     final List<ObjectSpecification> parameters) {
   outer:
   for (int i = 0; i < availableActions.size(); i++) {
     final ObjectAction action = availableActions.get(i);
     if (action.getActions().size() > 0) {
       // deal with action set
       final ObjectAction a = getAction(action.getActions(), type, actionName, parameters);
       if (a != null) {
         return a;
       }
     } else {
       // regular action
       if (!action.getType().equals(type)) {
         continue outer;
       }
       if (actionName != null && !actionName.equals(action.getId())) {
         continue outer;
       }
       if (action.getParameters().size() != parameters.size()) {
         continue outer;
       }
       for (int j = 0; j < parameters.size(); j++) {
         if (!parameters.get(j).isOfType(action.getParameters().get(j).getSpecification())) {
           continue outer;
         }
       }
       return action;
     }
   }
   return null;
 }
 /** @param serviceAction - number of the parameter that matches, or -1 if none. */
 private int contributeeParameterMatchOf(final ObjectAction serviceAction) {
   final List<ObjectActionParameter> params = serviceAction.getParameters();
   for (final ObjectActionParameter param : params) {
     if (isOfType(param.getSpecification())) {
       return param.getNumber();
     }
   }
   return -1;
 }
示例#14
0
  /**
   * Invokes the action for the object (checking it is visible) and then delegates to the {@link
   * org.apache.isis.viewer.restfulobjects.rendering.service.RepresentationService} to render a
   * representation of the result of that action.
   *
   * <p>The action must have {@link org.apache.isis.applib.annotation.ActionSemantics.Of#IDEMPOTENT
   * idempotent} semantics otherwise an error response is thrown.
   */
  public Response invokeActionIdempotent(
      final String actionId, final JsonRepresentation arguments) {

    final ObjectAdapterAccessHelper accessHelper =
        new ObjectAdapterAccessHelper(representationServiceContext, objectAdapter);

    final ObjectAction action =
        accessHelper.getObjectActionThatIsVisibleForIntent(
            actionId, ObjectAdapterAccessHelper.Intent.MUTATE);

    final ActionSemantics.Of actionSemantics = action.getSemantics();
    if (!actionSemantics.isIdempotentInNature()) {
      throw RestfulObjectsApplicationException.createWithMessage(
          RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED,
          "Method not allowed; action '%s' is not idempotent",
          action.getId());
    }
    return invokeActionUsingAdapters(action, arguments, ActionResultReprRenderer.SelfLink.EXCLUDED);
  }
示例#15
0
 // unused
 static String roSpecForResponseOf(final ObjectAction action) {
   final ActionSemantics.Of semantics = action.getSemantics();
   switch (semantics) {
     case SAFE_AND_REQUEST_CACHEABLE:
     case SAFE:
       return "19.2";
     case IDEMPOTENT:
     case IDEMPOTENT_ARE_YOU_SURE:
       return "19.3";
     default:
       return "19.4";
   }
 }
  /**
   * Synthesises {@link ObjectAssociation}s from matching {@link ObjectAction}s of any of the
   * services that accept one parameter
   */
  private List<ObjectAssociation> createContributeeAssociations(
      final ObjectAdapter serviceAdapter) {

    final ObjectSpecification specification = serviceAdapter.getSpecification();
    final List<ObjectAction> serviceActions =
        specification.getObjectActions(
            ActionType.USER, Contributed.INCLUDED, Filters.<ObjectAction>any());

    final List<ObjectActionImpl> contributedActions = Lists.newArrayList();
    for (final ObjectAction serviceAction : serviceActions) {
      if (isAlwaysHidden(serviceAction)) {
        continue;
      }
      final NotContributedFacet notContributed = serviceAction.getFacet(NotContributedFacet.class);
      if (notContributed != null && notContributed.toAssociations()) {
        continue;
      }
      if (!serviceAction.hasReturn()) {
        continue;
      }
      if (serviceAction.getParameterCount() != 1
          || contributeeParameterMatchOf(serviceAction) == -1) {
        continue;
      }
      if (!(serviceAction instanceof ObjectActionImpl)) {
        continue;
      }
      if (!serviceAction.getSemantics().isSafeInNature()) {
        continue;
      }
      contributedActions.add((ObjectActionImpl) serviceAction);
    }

    return Lists.newArrayList(
        Iterables.transform(
            contributedActions, createContributeeAssociationFunctor(serviceAdapter, this)));
  }
  @SuppressWarnings({"rawtypes"})
  private void postEvent(
      final ObjectAction owningAction,
      final ObjectAdapter targetAdapter,
      final ObjectAdapter[] argumentAdapters) {

    try {
      final Class type = eventType;
      Identifier actionIdentifier = owningAction.getIdentifier();
      final Object source = AdapterUtils.unwrap(targetAdapter);
      final Object[] arguments = AdapterUtils.unwrap(argumentAdapters);
      @SuppressWarnings("unchecked")
      final ActionInvokedEvent<?> event =
          org.apache.isis.core.metamodel.facets.actions.event.PostsActionInvokedEventFacet.Util
              .newEvent(type, source, actionIdentifier, arguments);
      getEventBusService().post(event);
    } catch (Exception e) {
      throw new FatalException(e);
    }
  }
示例#18
0
  // UNUSED
  void appendServiceActionPromptTo(final ObjectProperty serviceMembers, final ObjectAction action) {
    String actionId = action.getId();

    serviceMembers.property(
        actionId,
        new ObjectProperty()
            .property("id", stringPropertyEnum(actionId))
            .property("memberType", stringPropertyEnum("action"))
            .property(
                "links",
                new ObjectProperty()
                    .property(
                        "rel",
                        stringPropertyEnum(
                            String.format(
                                "urn:org.restfulobjects:rels/details;action=%s", actionId)))
                    .property("href", stringPropertyEnum(String.format("actions/%s", actionId))))
            .property("method", stringPropertyEnum("GET"))
            .property(
                "type",
                stringPropertyEnum(
                    "application/json;profile=urn:org.restfulobjects:repr-types/object-action")));
  }
示例#19
0
  void appendObjectActionInvokePath(
      final ObjectSpecification objectSpec, final ObjectAction objectAction) {

    final String objectType = objectTypeFor(objectSpec);
    final String actionId = objectAction.getId();

    final List<ObjectActionParameter> parameters = objectAction.getParameters();
    final Path path = new Path();
    swagger.path(
        String.format("/objects/%s/{objectId}/actions/%s/invoke", objectType, actionId), path);

    final String tag = tagFor(objectType, null);
    final Operation invokeOperation =
        new Operation()
            .tag(tag)
            .description(
                Util.roSpec("19.1") + ": (invoke) resource of " + objectType + "#" + actionId)
            .parameter(new PathParameter().name("objectId").type("string"))
            .produces("application/json;profile=urn:org.apache.isis/v1")
            .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
            .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result");

    final ActionSemantics.Of semantics = objectAction.getSemantics();
    if (semantics.isSafeInNature()) {
      path.get(invokeOperation);

      for (final ObjectActionParameter parameter : parameters) {
        invokeOperation.parameter(
            new QueryParameter()
                .name(parameter.getId())
                .description(
                    Util.roSpec("2.9.1")
                        + (!Strings.isNullOrEmpty(parameter.getDescription())
                            ? (": " + parameter.getDescription())
                            : ""))
                .required(false)
                .type("string"));
      }
      if (!parameters.isEmpty()) {
        invokeOperation.parameter(
            new QueryParameter()
                .name("x-isis-querystring")
                .description(
                    Util.roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
                .required(false)
                .type("string"));
      }

    } else {
      if (semantics.isIdempotentInNature()) {
        path.put(invokeOperation);
      } else {
        path.post(invokeOperation);
      }

      final ModelImpl bodyParam = new ModelImpl().type("object");
      for (final ObjectActionParameter parameter : parameters) {

        final ObjectSpecification specification = parameter.getSpecification();
        final Property valueProperty =
            specification.isValue() ? modelFor(specification) : refToLinkModel();
        bodyParam.property(
            parameter.getId(), new ObjectProperty().property("value", valueProperty));
      }

      invokeOperation
          .consumes("application/json")
          .parameter(new BodyParameter().name("body").schema(bodyParam));
    }

    invokeOperation.response(
        200,
        new Response()
            .description(objectType + "#" + actionId)
            .schema(actionReturnTypeFor(objectAction)));
  }
示例#20
0
  void appendServiceActionInvokePath(
      final ObjectSpecification serviceSpec, final ObjectAction serviceAction) {

    final String serviceId = serviceIdFor(serviceSpec);
    final String actionId = serviceAction.getId();

    final List<ObjectActionParameter> parameters = serviceAction.getParameters();
    final Path path = new Path();
    swagger.path(String.format("/services/%s/actions/%s/invoke", serviceId, actionId), path);

    final String tag = tagFor(serviceId, "> services");
    final Operation invokeOperation =
        new Operation()
            .tag(tag)
            .description(
                Util.roSpec("19.1") + ": (invoke) resource of " + serviceId + "#" + actionId)
            .produces("application/json;profile=urn:org.apache.isis/v1")
            .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
            .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result");

    final ActionSemantics.Of semantics = serviceAction.getSemantics();
    if (semantics.isSafeInNature()) {
      path.get(invokeOperation);

      for (final ObjectActionParameter parameter : parameters) {
        invokeOperation.parameter(
            new QueryParameter()
                .name(parameter.getId())
                .description(
                    Util.roSpec("2.9.1")
                        + (!Strings.isNullOrEmpty(parameter.getDescription())
                            ? (": " + parameter.getDescription())
                            : ""))
                .required(false)
                .type("string"));
      }
      if (!parameters.isEmpty()) {
        invokeOperation.parameter(
            new QueryParameter()
                .name("x-isis-querystring")
                .description(
                    Util.roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
                .required(false)
                .type("string"));
      }

    } else {
      if (semantics.isIdempotentInNature()) {
        path.put(invokeOperation);
      } else {
        path.post(invokeOperation);
      }

      final ModelImpl bodyParam = new ModelImpl().type("object");
      for (final ObjectActionParameter parameter : parameters) {

        final Property valueProperty;
        // TODO: need to switch on parameter's type and create appropriate impl of valueProperty
        // if(parameter.getSpecification().isValue()) ...
        valueProperty = stringProperty();

        bodyParam.property(
            parameter.getId(), new ObjectProperty().property("value", valueProperty));
      }

      invokeOperation
          .consumes("application/json")
          .parameter(new BodyParameter().name("body").schema(bodyParam));
    }

    invokeOperation.response(
        200,
        new Response()
            .description(
                serviceId
                    + "#"
                    + actionId
                    + " , if Accept: application/json;profile=urn:org.apache.isis/v1")
            .schema(actionReturnTypeFor(serviceAction)));
  }
示例#21
0
  private static void actionDetails(
      final ObjectAction objectAction,
      final int indent,
      final int count,
      final DebugBuilder debugBuilder) {
    debugBuilder.appendln(
        (count + 1) + "." + objectAction.getId() + " (" + objectAction.getClass().getName() + ")");
    debugBuilder.indent();
    try {
      if (objectAction.getDescription() != null && !objectAction.getDescription().equals("")) {
        debugBuilder.appendln("Description", objectAction.getDescription());
      }
      debugBuilder.appendln("ID", objectAction.getId());

      debugBuilder.appendln(objectAction.debugData());
      debugBuilder.appendln("On type", objectAction.getOnType());

      final Class<? extends Facet>[] facets = objectAction.getFacetTypes();
      if (facets.length > 0) {
        debugBuilder.appendln("Facets");
        debugBuilder.indent();
        for (final Class<? extends Facet> facet : facets) {
          debugBuilder.appendln(objectAction.getFacet(facet).toString());
        }
        debugBuilder.unindent();
      }

      final ObjectSpecification returnType = objectAction.getReturnType();
      debugBuilder.appendln("Returns", returnType == null ? "VOID" : returnType.toString());

      final List<ObjectActionParameter> parameters = objectAction.getParameters();
      if (parameters.size() == 0) {
        debugBuilder.appendln("Parameters", "none");
      } else {
        debugBuilder.appendln("Parameters");
        debugBuilder.indent();
        final List<ObjectActionParameter> p = objectAction.getParameters();
        for (int j = 0; j < parameters.size(); j++) {
          debugBuilder.append(p.get(j).getName());
          debugBuilder.append(" (");
          debugBuilder.append(parameters.get(j).getSpecification().getFullIdentifier());
          debugBuilder.appendln(")");
          debugBuilder.indent();
          final Class<? extends Facet>[] parameterFacets = p.get(j).getFacetTypes();
          for (final Class<? extends Facet> parameterFacet : parameterFacets) {
            debugBuilder.appendln(p.get(j).getFacet(parameterFacet).toString());
          }
          debugBuilder.unindent();
        }
        debugBuilder.unindent();
      }
    } catch (final RuntimeException e) {
      debugBuilder.appendException(e);
    }

    debugBuilder.unindent();
  }
示例#22
0
 public String getNumParams() {
   return action != null ? "" + action.getParameterCount() : "";
 }