/** * 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; } }
// 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"; } }
/** * 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); }
/** * 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))); }
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))); }
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))); }