Esempio n. 1
0
 /**
  * Replicates the request to all nodes in the cluster using the provided method and entity. The
  * headers used will be those provided by the {@link #getHeaders()} method. The URI that will be
  * used will be that provided by the {@link #getAbsolutePath()} method
  *
  * @param method the HTTP method to use
  * @param entity the entity to replicate
  * @param headersToOverride the headers to override
  * @return the response from the request
  */
 protected Response replicate(
     final String method, final Object entity, final Map<String, String> headersToOverride) {
   final URI path = getAbsolutePath();
   try {
     final Map<String, String> headers =
         headersToOverride == null ? getHeaders() : getHeaders(headersToOverride);
     return requestReplicator
         .replicate(method, path, entity, headers)
         .awaitMergedResponse()
         .getResponse();
   } catch (final InterruptedException ie) {
     return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
         .entity("Request to " + method + " " + path + " was interrupted")
         .type("text/plain")
         .build();
   }
 }
Esempio n. 2
0
  /**
   * Replicates the request to the given node
   *
   * @param method the HTTP method
   * @param entity the Entity to replicate
   * @param nodeUuid the UUID of the node to replicate the request to
   * @return the response from the node
   * @throws UnknownNodeException if the nodeUuid given does not map to any node in the cluster
   */
  protected Response replicate(
      final String method,
      final Object entity,
      final String nodeUuid,
      final Map<String, String> headersToOverride) {
    // since we're cluster we must specify the cluster node identifier
    if (nodeUuid == null) {
      throw new IllegalArgumentException("The cluster node identifier must be specified.");
    }

    final NodeIdentifier nodeId = clusterCoordinator.getNodeIdentifier(nodeUuid);
    if (nodeId == null) {
      throw new UnknownNodeException(
          "Cannot replicate request "
              + method
              + " "
              + getAbsolutePath()
              + " to node with ID "
              + nodeUuid
              + " because the specified node does not exist.");
    }

    final Set<NodeIdentifier> targetNodes = Collections.singleton(nodeId);
    final URI path = getAbsolutePath();
    try {
      final Map<String, String> headers =
          headersToOverride == null ? getHeaders() : getHeaders(headersToOverride);
      return requestReplicator
          .replicate(targetNodes, method, path, entity, headers)
          .awaitMergedResponse()
          .getResponse();
    } catch (final InterruptedException ie) {
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
          .entity("Request to " + method + " " + path + " was interrupted")
          .type("text/plain")
          .build();
    }
  }
  @Override
  public DownloadableContent getContent(final ContentRequestContext request) {
    // if clustered, send request to cluster manager
    if (properties.isClustered()
        && clusterCoordinator != null
        && clusterCoordinator.isConnected()) {
      // get the URI
      URI dataUri;
      try {
        dataUri = new URI(request.getDataUri());
      } catch (final URISyntaxException use) {
        throw new ClusterRequestException(use);
      }

      // set the request parameters
      final MultivaluedMap<String, String> parameters = new MultivaluedMapImpl();
      parameters.add(CLIENT_ID_PARAM, request.getClientId());

      // set the headers
      final Map<String, String> headers = new HashMap<>();
      if (StringUtils.isNotBlank(request.getProxiedEntitiesChain())) {
        headers.put("X-ProxiedEntitiesChain", request.getProxiedEntitiesChain());
      }

      // add the user's authorities (if any) to the headers
      final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
      if (authentication != null) {
        final Object userDetailsObj = authentication.getPrincipal();
        if (userDetailsObj instanceof NiFiUserDetails) {
          // serialize user details object
          final String hexEncodedUserDetails =
              WebUtils.serializeObjectToHex((Serializable) userDetailsObj);

          // put serialized user details in header
          headers.put("X-ProxiedEntityUserDetails", hexEncodedUserDetails);
        }
      }

      // ensure we were able to detect the cluster node id
      if (request.getClusterNodeId() == null) {
        throw new IllegalArgumentException("Unable to determine the which node has the content.");
      }

      // get the target node and ensure it exists
      final NodeIdentifier nodeId =
          clusterCoordinator.getNodeIdentifier(request.getClusterNodeId());
      final Set<NodeIdentifier> targetNodes = Collections.singleton(nodeId);

      // replicate the request to the specific node
      NodeResponse nodeResponse;
      try {
        nodeResponse =
            requestReplicator
                .replicate(targetNodes, HttpMethod.GET, dataUri, parameters, headers)
                .awaitMergedResponse();
      } catch (InterruptedException e) {
        throw new IllegalClusterStateException(
            "Interrupted while waiting for a response from node");
      }

      final ClientResponse clientResponse = nodeResponse.getClientResponse();
      final MultivaluedMap<String, String> responseHeaders = clientResponse.getHeaders();

      // ensure an appropriate response
      if (Status.NOT_FOUND.getStatusCode() == clientResponse.getStatusInfo().getStatusCode()) {
        throw new ResourceNotFoundException(clientResponse.getEntity(String.class));
      } else if (Status.FORBIDDEN.getStatusCode() == clientResponse.getStatusInfo().getStatusCode()
          || Status.UNAUTHORIZED.getStatusCode()
              == clientResponse.getStatusInfo().getStatusCode()) {
        throw new AccessDeniedException(clientResponse.getEntity(String.class));
      } else if (Status.OK.getStatusCode() != clientResponse.getStatusInfo().getStatusCode()) {
        throw new IllegalStateException(clientResponse.getEntity(String.class));
      }

      // get the file name
      final String contentDisposition = responseHeaders.getFirst("Content-Disposition");
      final String filename = StringUtils.substringBetween(contentDisposition, "filename=\"", "\"");

      // get the content type
      final String contentType = responseHeaders.getFirst("Content-Type");

      // create the downloadable content
      return new DownloadableContent(filename, contentType, clientResponse.getEntityInputStream());
    } else {
      // example URIs:
      // http://localhost:8080/nifi-api/provenance/events/{id}/content/{input|output}
      // http://localhost:8080/nifi-api/flowfile-queues/{uuid}/flowfiles/{uuid}/content

      // get just the context path for comparison
      final String dataUri = StringUtils.substringAfter(request.getDataUri(), "/nifi-api");
      if (StringUtils.isBlank(dataUri)) {
        throw new IllegalArgumentException("The specified data reference URI is not valid.");
      }

      // flowfile listing content
      final Matcher flowFileMatcher = FLOWFILE_CONTENT_URI_PATTERN.matcher(dataUri);
      if (flowFileMatcher.matches()) {
        final String connectionId = flowFileMatcher.group(1);
        final String flowfileId = flowFileMatcher.group(2);

        return getFlowFileContent(connectionId, flowfileId, dataUri);
      }

      // provenance event content
      final Matcher provenanceMatcher = PROVENANCE_CONTENT_URI_PATTERN.matcher(dataUri);
      if (provenanceMatcher.matches()) {
        try {
          final Long eventId = Long.parseLong(provenanceMatcher.group(1));
          final ContentDirection direction =
              ContentDirection.valueOf(provenanceMatcher.group(2).toUpperCase());

          return getProvenanceEventContent(eventId, dataUri, direction);
        } catch (final IllegalArgumentException iae) {
          throw new IllegalArgumentException("The specified data reference URI is not valid.");
        }
      }

      // invalid uri
      throw new IllegalArgumentException("The specified data reference URI is not valid.");
    }
  }