mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-926: Improve response plumbing through to user.
This commit is contained in:
@@ -68,10 +68,21 @@ public class ConnectionDirectory extends JDBCDirectory<Connection> {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void update(Connection object) throws GuacamoleException {
|
public void update(Connection object) throws GuacamoleException {
|
||||||
|
|
||||||
|
// If the provided connection is already an internal type, update
|
||||||
|
// using the internal method
|
||||||
|
if (object instanceof ModeledConnection) {
|
||||||
ModeledConnection connection = (ModeledConnection) object;
|
ModeledConnection connection = (ModeledConnection) object;
|
||||||
connectionService.updateObject(getCurrentUser(), connection);
|
connectionService.updateObject(getCurrentUser(), connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the type is not already the expected internal type, use the
|
||||||
|
// external update method
|
||||||
|
else {
|
||||||
|
connectionService.updateExternalObject(getCurrentUser(), object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void remove(String identifier) throws GuacamoleException {
|
public void remove(String identifier) throws GuacamoleException {
|
||||||
|
@@ -90,4 +90,10 @@ public class DelegatingDirectory<ObjectType extends Identifiable>
|
|||||||
directory.remove(identifier);
|
directory.remove(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tryAtomically(AtomicDirectoryOperation<ObjectType> operation)
|
||||||
|
throws GuacamoleException {
|
||||||
|
directory.tryAtomically(operation);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,8 @@ package org.apache.guacamole.rest;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.guacamole.GuacamoleClientException;
|
import org.apache.guacamole.GuacamoleClientException;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleResourceNotFoundException;
|
import org.apache.guacamole.GuacamoleResourceNotFoundException;
|
||||||
@@ -31,6 +33,8 @@ import org.apache.guacamole.language.TranslatableMessage;
|
|||||||
import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
|
import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
|
||||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
||||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatchFailureException;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatchOutcome;
|
||||||
import org.apache.guacamole.tunnel.GuacamoleStreamException;
|
import org.apache.guacamole.tunnel.GuacamoleStreamException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,6 +75,12 @@ public class APIError {
|
|||||||
*/
|
*/
|
||||||
private final Collection<Field> expected;
|
private final Collection<Field> expected;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The outcome of each patch in the associated request, if this was a
|
||||||
|
* JSON Patch request. Otherwise null.
|
||||||
|
*/
|
||||||
|
private List<APIPatchOutcome> patches = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of error that occurred.
|
* The type of error that occurred.
|
||||||
*/
|
*/
|
||||||
@@ -202,13 +212,14 @@ public class APIError {
|
|||||||
this.translatableMessage = translatable.getTranslatableMessage();
|
this.translatableMessage = translatable.getTranslatableMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle patch exceptions, need a bunch of JSON saying which things failed
|
|
||||||
|
|
||||||
// Use generic translation string if message is not translated
|
// Use generic translation string if message is not translated
|
||||||
else
|
else
|
||||||
this.translatableMessage = new TranslatableMessage(UNTRANSLATED_MESSAGE_KEY,
|
this.translatableMessage = new TranslatableMessage(UNTRANSLATED_MESSAGE_KEY,
|
||||||
Collections.singletonMap(UNTRANSLATED_MESSAGE_VARIABLE_NAME, this.message));
|
Collections.singletonMap(UNTRANSLATED_MESSAGE_VARIABLE_NAME, this.message));
|
||||||
|
|
||||||
|
if (exception instanceof APIPatchFailureException)
|
||||||
|
this.patches = ((APIPatchFailureException) exception).getPatches();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,6 +256,18 @@ public class APIError {
|
|||||||
return expected;
|
return expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the outcome for every patch in the request, if the request was
|
||||||
|
* a JSON patch request. Otherwise, null.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The outcome for every patch if responding to a JSON Patch request,
|
||||||
|
* otherwise null.
|
||||||
|
*/
|
||||||
|
public List<APIPatchOutcome> getPatches() {
|
||||||
|
return patches;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a human-readable error message describing the error that
|
* Returns a human-readable error message describing the error that
|
||||||
* occurred.
|
* occurred.
|
||||||
|
@@ -53,8 +53,12 @@ import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
|
|||||||
import org.apache.guacamole.net.event.DirectoryEvent;
|
import org.apache.guacamole.net.event.DirectoryEvent;
|
||||||
import org.apache.guacamole.net.event.DirectoryFailureEvent;
|
import org.apache.guacamole.net.event.DirectoryFailureEvent;
|
||||||
import org.apache.guacamole.net.event.DirectorySuccessEvent;
|
import org.apache.guacamole.net.event.DirectorySuccessEvent;
|
||||||
import org.apache.guacamole.rest.APIPatch;
|
|
||||||
import org.apache.guacamole.rest.event.ListenerService;
|
import org.apache.guacamole.rest.event.ListenerService;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatch;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatchError;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatchFailureException;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatchOutcome;
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatchResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A REST resource which abstracts the operations available on all Guacamole
|
* A REST resource which abstracts the operations available on all Guacamole
|
||||||
@@ -344,7 +348,20 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
return resourceFactory;
|
return resourceFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter and sanitize the provided external object, translate to the
|
||||||
|
* internal type, and return the translated internal object.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* The external object to filter and translate.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The filtered and translated internal object.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while filtering or translating the external
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
private InternalType filterAndTranslate(ExternalType object)
|
private InternalType filterAndTranslate(ExternalType object)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
@@ -412,11 +429,22 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs while adding, updating, or removing objects.
|
* If an error occurs while adding, updating, or removing objects.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A response describing the outcome of each patch. Only the identifier
|
||||||
|
* of each patched object will be included in the response, not the
|
||||||
|
* full object.
|
||||||
*/
|
*/
|
||||||
@PATCH
|
@PATCH
|
||||||
public void patchObjects(List<APIPatch<ExternalType>> patches)
|
public APIPatchResponse patchObjects(List<APIPatch<ExternalType>> patches)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
// An outcome for each patch included in the request. This list
|
||||||
|
// may include both success and failure responses, though the
|
||||||
|
// presense of any failure would indicated that the entire
|
||||||
|
// request has failed and no changes have been made.
|
||||||
|
List<APIPatchOutcome> patchOutcomes = new ArrayList<>();
|
||||||
|
|
||||||
// Perform all requested operations atomically
|
// Perform all requested operations atomically
|
||||||
directory.tryAtomically(new AtomicDirectoryOperation<InternalType>() {
|
directory.tryAtomically(new AtomicDirectoryOperation<InternalType>() {
|
||||||
|
|
||||||
@@ -432,13 +460,16 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
"Atomic operations are not supported. " +
|
"Atomic operations are not supported. " +
|
||||||
"The patch cannot be executed.");
|
"The patch cannot be executed.");
|
||||||
|
|
||||||
|
|
||||||
// Keep a list of all objects that have been successfully
|
// Keep a list of all objects that have been successfully
|
||||||
// added, updated, or removed
|
// added, updated, or removed
|
||||||
Collection<InternalType> addedObjects = new ArrayList<>();
|
Collection<InternalType> addedObjects = new ArrayList<>();
|
||||||
Collection<InternalType> updatedObjects = new ArrayList<>();
|
Collection<InternalType> updatedObjects = new ArrayList<>();
|
||||||
Collection<String> removedIdentifiers = new ArrayList<>();
|
Collection<String> removedIdentifiers = new ArrayList<>();
|
||||||
|
|
||||||
|
// A list of all responses associated with the successful
|
||||||
|
// creation of new objects
|
||||||
|
List<APIPatchOutcome> creationSuccesses = new ArrayList<>();
|
||||||
|
|
||||||
// True if any operation in the patch failed. Any failure will
|
// True if any operation in the patch failed. Any failure will
|
||||||
// fail the request, though won't result in immediate stoppage
|
// fail the request, though won't result in immediate stoppage
|
||||||
// since more errors may yet be uncovered.
|
// since more errors may yet be uncovered.
|
||||||
@@ -465,14 +496,33 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
// Add the object to the list if addition was successful
|
// Add the object to the list if addition was successful
|
||||||
addedObjects.add(internal);
|
addedObjects.add(internal);
|
||||||
|
|
||||||
|
// Add a success outcome describing the object creation
|
||||||
|
APIPatchOutcome response = new APIPatchOutcome(
|
||||||
|
patch.getOp(), internal.getIdentifier(), path);
|
||||||
|
patchOutcomes.add(response);
|
||||||
|
creationSuccesses.add(response);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (GuacamoleException | RuntimeException | Error e) {
|
catch (GuacamoleException | RuntimeException | Error e) {
|
||||||
|
failed = true;
|
||||||
fireDirectoryFailureEvent(
|
fireDirectoryFailureEvent(
|
||||||
DirectoryEvent.Operation.ADD,
|
DirectoryEvent.Operation.ADD,
|
||||||
internal.getIdentifier(), internal, e);
|
internal.getIdentifier(), internal, e);
|
||||||
|
|
||||||
// TODO: Save the error for later inclusion in a big JSON error response
|
/*
|
||||||
failed = true;
|
* If the failure represents an understood issue,
|
||||||
|
* create a failure outcome for this failed patch.
|
||||||
|
*/
|
||||||
|
if (e instanceof GuacamoleException)
|
||||||
|
patchOutcomes.add(new APIPatchError(
|
||||||
|
patch.getOp(), null, path,
|
||||||
|
((GuacamoleException) e).getMessage()));
|
||||||
|
|
||||||
|
// If an unexpected failure occurs, fall through to the
|
||||||
|
// standard API error handling
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -489,14 +539,33 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
|
|
||||||
// Add the object to the list if the update was successful
|
// Add the object to the list if the update was successful
|
||||||
updatedObjects.add(internal);
|
updatedObjects.add(internal);
|
||||||
|
|
||||||
|
// Add a success outcome describing the object update
|
||||||
|
APIPatchOutcome response = new APIPatchOutcome(
|
||||||
|
patch.getOp(), internal.getIdentifier(), path);
|
||||||
|
patchOutcomes.add(response);
|
||||||
|
creationSuccesses.add(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (GuacamoleException | RuntimeException | Error e) {
|
catch (GuacamoleException | RuntimeException | Error e) {
|
||||||
|
failed = true;
|
||||||
fireDirectoryFailureEvent(
|
fireDirectoryFailureEvent(
|
||||||
DirectoryEvent.Operation.UPDATE,
|
DirectoryEvent.Operation.UPDATE,
|
||||||
internal.getIdentifier(), internal, e);
|
internal.getIdentifier(), internal, e);
|
||||||
|
|
||||||
// TODO: Save the error for later inclusion in a big JSON error response
|
/*
|
||||||
failed = true;
|
* If the failure represents an understood issue,
|
||||||
|
* create a failure outcome for this failed patch.
|
||||||
|
*/
|
||||||
|
if (e instanceof GuacamoleException)
|
||||||
|
patchOutcomes.add(new APIPatchError(
|
||||||
|
patch.getOp(), internal.getIdentifier(), path,
|
||||||
|
((GuacamoleException) e).getMessage()));
|
||||||
|
|
||||||
|
// If an unexpected failure occurs, fall through to the
|
||||||
|
// standard API error handling
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,22 +581,51 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
|
|
||||||
// Add the object to the list if the removal was successful
|
// Add the object to the list if the removal was successful
|
||||||
removedIdentifiers.add(identifier);
|
removedIdentifiers.add(identifier);
|
||||||
|
|
||||||
|
// Add a success outcome describing the object removal
|
||||||
|
APIPatchOutcome response = new APIPatchOutcome(
|
||||||
|
patch.getOp(), identifier, path);
|
||||||
|
patchOutcomes.add(response);
|
||||||
|
creationSuccesses.add(response);
|
||||||
}
|
}
|
||||||
catch (GuacamoleException | RuntimeException | Error e) {
|
catch (GuacamoleException | RuntimeException | Error e) {
|
||||||
fireDirectoryFailureEvent(
|
|
||||||
DirectoryEvent.Operation.UPDATE, identifier, null, e);
|
|
||||||
|
|
||||||
// TODO: Save the error for later inclusion in a big JSON error response
|
|
||||||
failed = true;
|
failed = true;
|
||||||
|
fireDirectoryFailureEvent(
|
||||||
|
DirectoryEvent.Operation.REMOVE,
|
||||||
|
identifier, null, e);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the failure represents an understood issue,
|
||||||
|
* create a failure outcome for this failed patch.
|
||||||
|
*/
|
||||||
|
if (e instanceof GuacamoleException)
|
||||||
|
patchOutcomes.add(new APIPatchError(
|
||||||
|
patch.getOp(), identifier, path,
|
||||||
|
((GuacamoleException) e).getMessage()));
|
||||||
|
|
||||||
|
// If an unexpected failure occurs, fall through to the
|
||||||
|
// standard API error handling
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any operation failed, fail now
|
// If any operation failed
|
||||||
if (failed) {
|
if (failed) {
|
||||||
throw new GuacamoleClientException(
|
|
||||||
"oh noes the patch batch failed");
|
// Any identifiers for objects created during this request
|
||||||
|
// will no longer be valid, since the creation of those
|
||||||
|
// objects will be rolled back.
|
||||||
|
creationSuccesses.forEach(
|
||||||
|
response -> response.clearIdentifier());
|
||||||
|
|
||||||
|
// Return an error response, including any failures that
|
||||||
|
// caused the failure of any patch in the request
|
||||||
|
throw new APIPatchFailureException(
|
||||||
|
"The provided patches failed to apply.", patchOutcomes);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire directory success events for each created object
|
// Fire directory success events for each created object
|
||||||
@@ -536,7 +634,8 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
|
|
||||||
InternalType internal = addedIterator.next();
|
InternalType internal = addedIterator.next();
|
||||||
fireDirectorySuccessEvent(
|
fireDirectorySuccessEvent(
|
||||||
DirectoryEvent.Operation.ADD, internal.getIdentifier(), internal);
|
DirectoryEvent.Operation.ADD,
|
||||||
|
internal.getIdentifier(), internal);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +645,8 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
|
|
||||||
InternalType internal = updatedIterator.next();
|
InternalType internal = updatedIterator.next();
|
||||||
fireDirectorySuccessEvent(
|
fireDirectorySuccessEvent(
|
||||||
DirectoryEvent.Operation.UPDATE, internal.getIdentifier(), internal);
|
DirectoryEvent.Operation.UPDATE,
|
||||||
|
internal.getIdentifier(), internal);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,7 +656,8 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
|
|
||||||
String identifier = removedIterator.next();
|
String identifier = removedIterator.next();
|
||||||
fireDirectorySuccessEvent(
|
fireDirectorySuccessEvent(
|
||||||
DirectoryEvent.Operation.UPDATE, identifier, null);
|
DirectoryEvent.Operation.UPDATE,
|
||||||
|
identifier, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,9 +665,8 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: JSON response indicating which things were changed
|
// Return a list of outcomes, one for each patch in the request
|
||||||
// NOTE: IDs are assigned at creation time so a user of the API
|
return new APIPatchResponse(patchOutcomes);
|
||||||
// needs this response if they want to be able to actually use them
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ import javax.ws.rs.core.MediaType;
|
|||||||
import org.apache.guacamole.GuacamoleClientException;
|
import org.apache.guacamole.GuacamoleClientException;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.net.auth.RelatedObjectSet;
|
import org.apache.guacamole.net.auth.RelatedObjectSet;
|
||||||
import org.apache.guacamole.rest.APIPatch;
|
import org.apache.guacamole.rest.jsonpatch.APIPatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A REST resource which abstracts the operations available on arbitrary sets
|
* A REST resource which abstracts the operations available on arbitrary sets
|
||||||
|
@@ -17,11 +17,11 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.rest;
|
package org.apache.guacamole.rest.jsonpatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object for representing the body of a HTTP PATCH method.
|
* An object for representing an entry within the body of a
|
||||||
* See https://tools.ietf.org/html/rfc6902
|
* JSON PATCH request. See https://tools.ietf.org/html/rfc6902
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* The type of object being patched.
|
* The type of object being patched.
|
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.rest.jsonpatch;
|
||||||
|
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatch.Operation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A failure outcome associated with a particular patch within a JSON Patch
|
||||||
|
* request. This status indicates that a particular patch failed to apply,
|
||||||
|
* and includes the error describing the failure, along with the operation and
|
||||||
|
* path from the original patch, and the identifier of the object
|
||||||
|
* referenced by the original patch.
|
||||||
|
*/
|
||||||
|
public class APIPatchError extends APIPatchOutcome {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The error associated with the submitted patch.
|
||||||
|
*/
|
||||||
|
private final String error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a failure status associated with a submitted patch from a JSON
|
||||||
|
* patch API request.
|
||||||
|
*
|
||||||
|
* @param op
|
||||||
|
* The operation requested by the failed patch.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the object associated with the failed patch. If
|
||||||
|
* the patch failed to create a new object, this will be null.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The patch from the failed patch.
|
||||||
|
*
|
||||||
|
* @param error
|
||||||
|
* The error message associated with the failure that prevented the
|
||||||
|
* patch from applying.
|
||||||
|
*/
|
||||||
|
public APIPatchError(
|
||||||
|
Operation op, String identifier, String path, String error) {
|
||||||
|
super(op, identifier, path);
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the error associated with the patch failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The error associated with the patch failure.
|
||||||
|
*/
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.rest.jsonpatch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.guacamole.GuacamoleClientException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception describing a failure to apply the patches from a JSON Patch
|
||||||
|
* request. A list of outcomes is included, one for each patch in the request.
|
||||||
|
*/
|
||||||
|
public class APIPatchFailureException extends GuacamoleClientException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of outcomes, each one corresponding to a patch in the request
|
||||||
|
* corresponding to this response. This may include a mix of successes and
|
||||||
|
* failures. Any failure will result in a failure of the entire request
|
||||||
|
* since JSON Patch requests are handled atomically.
|
||||||
|
*/
|
||||||
|
public final List<APIPatchOutcome> patches;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new patch request failure with the provided list of outcomes
|
||||||
|
* for individual patches.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* A human-readable message describing the overall request failure.
|
||||||
|
*
|
||||||
|
* @param patches
|
||||||
|
* A list of patch outcomes, one for each patch in the request
|
||||||
|
* associated with this response.
|
||||||
|
*/
|
||||||
|
public APIPatchFailureException(
|
||||||
|
String message, List<APIPatchOutcome> patches) {
|
||||||
|
|
||||||
|
super(message );
|
||||||
|
this.patches = patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the outcome for each patch in the request corresponding to this
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
public List<APIPatchOutcome> getPatches() {
|
||||||
|
return patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.rest.jsonpatch;
|
||||||
|
|
||||||
|
import org.apache.guacamole.rest.jsonpatch.APIPatch.Operation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A successful outcome associated with a particular patch within a JSON Patch
|
||||||
|
* request. The outcome contains the operation requested by the original patch,
|
||||||
|
* the path from the original patch, and the identifier of the object corresponding
|
||||||
|
* to the value from the original patch.
|
||||||
|
*
|
||||||
|
* The purpose of this class is to present a relatively lightweight outcome for
|
||||||
|
* the user who submitted the Patch request. Rather than including the full
|
||||||
|
* contents of the value, only the identifier is included, allowing the user to
|
||||||
|
* determine the identifier of any newly-created objects as part of the request.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class APIPatchOutcome {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The requested operation for the patch corresponding to this outcome.
|
||||||
|
*/
|
||||||
|
private final Operation op;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier for the value in patch corresponding to this outcome.
|
||||||
|
* If the value in the patch was null, this identifier should also be null.
|
||||||
|
*/
|
||||||
|
private String identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path for the patch corresponding to this outcome.
|
||||||
|
*/
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an outcome associated with a submitted patch, as part of a JSON
|
||||||
|
* patch API request.
|
||||||
|
*
|
||||||
|
* @param op
|
||||||
|
* @param identifier
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
public APIPatchOutcome(Operation op, String identifier, String path) {
|
||||||
|
this.op = op;
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the identifier associated with this patch outcome. This must
|
||||||
|
* be done when an identifier in a outcome refers to a temporary object
|
||||||
|
* that was rolled back during processing of a request.
|
||||||
|
*/
|
||||||
|
public void clearIdentifier() {
|
||||||
|
this.identifier = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the requested operation for the patch corresponding to this
|
||||||
|
* outcome.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The requested operation for the patch corresponding to this outcome.
|
||||||
|
*/
|
||||||
|
public Operation getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path for the patch corresponding to this outcome.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The path for the patch corresponding to this outcome.
|
||||||
|
*/
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier for the value in patch corresponding to this
|
||||||
|
* outcome, or null if the value in the patch was null.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The identifier for the value in patch corresponding to this
|
||||||
|
* outcome, or null if the value was null.
|
||||||
|
*/
|
||||||
|
public String getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.rest.jsonpatch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A REST response describing the successful application of a JSON PATCH
|
||||||
|
* request to a directory. This consists of a list of outcomes, one for each
|
||||||
|
* patch within the request, in the same order.
|
||||||
|
*/
|
||||||
|
public class APIPatchResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of outcomes, each one corresponding to a patch in the request
|
||||||
|
* corresponding to this response.
|
||||||
|
*/
|
||||||
|
public final List<APIPatchOutcome> patches;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new patch response with the provided list of outcomes for
|
||||||
|
* individual patches.
|
||||||
|
*
|
||||||
|
* @param patches
|
||||||
|
* A list of patch outcomes, one for each patch in the request
|
||||||
|
* associated with this response.
|
||||||
|
*/
|
||||||
|
public APIPatchResponse(List<APIPatchOutcome> patches) {
|
||||||
|
this.patches = patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the outcome for each patch in the request corresponding to this
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
public List<APIPatchOutcome> getPatches() {
|
||||||
|
return patches;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classes related to JSON Patch HTTP requests or responses.
|
||||||
|
* See https://www.rfc-editor.org/rfc/rfc6902.
|
||||||
|
*/
|
||||||
|
package org.apache.guacamole.rest.jsonpatch;
|
@@ -31,7 +31,7 @@ import org.apache.guacamole.net.auth.Permissions;
|
|||||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||||
import org.apache.guacamole.net.auth.permission.Permission;
|
import org.apache.guacamole.net.auth.permission.Permission;
|
||||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||||
import org.apache.guacamole.rest.APIPatch;
|
import org.apache.guacamole.rest.jsonpatch.APIPatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A REST resource which abstracts the operations available on the permissions
|
* A REST resource which abstracts the operations available on the permissions
|
||||||
|
Reference in New Issue
Block a user