/**
   * Persist the supplied {@link JsonValue} {@code value} as the new state of this singleton
   * relationship on {@code resourceId}.
   *
   * <p><em>This is currently the only means of creating an instance of this singleton</em>
   *
   * @param context The context of this request
   * @param resourceId Id of the resource relation fields in value are to be memebers of
   * @param value A {@link JsonValue} map of relationship fields and their values
   * @return The persisted instance of {@code value}
   */
  @Override
  public Promise<JsonValue, ResourceException> setRelationshipValueForResource(
      Context context, String resourceId, JsonValue value) {
    if (value.isNotNull()) {
      try {
        final JsonValue id = value.get(FIELD_ID);

        // Update if we got an id, otherwise replace
        if (id != null && id.isNotNull()) {
          final UpdateRequest updateRequest = Requests.newUpdateRequest("", value);
          updateRequest.setAdditionalParameter(PARAM_FIRST_ID, resourceId);
          return updateInstance(context, value.get(FIELD_ID).asString(), updateRequest)
              .then(
                  new Function<ResourceResponse, JsonValue, ResourceException>() {
                    @Override
                    public JsonValue apply(ResourceResponse resourceResponse)
                        throws ResourceException {
                      return resourceResponse.getContent();
                    }
                  });
        } else { // no id, replace current instance
          clear(context, resourceId);

          final CreateRequest createRequest = Requests.newCreateRequest("", value);
          createRequest.setAdditionalParameter(PARAM_FIRST_ID, resourceId);
          return createInstance(context, createRequest)
              .then(
                  new Function<ResourceResponse, JsonValue, ResourceException>() {
                    @Override
                    public JsonValue apply(ResourceResponse resourceResponse)
                        throws ResourceException {
                      return resourceResponse.getContent();
                    }
                  });
        }
      } catch (ResourceException e) {
        return e.asPromise();
      }

    } else {
      clear(context, resourceId);
      return newResultPromise(json(null));
    }
  }
Example #2
0
 /**
  * Update a link.
  *
  * @throws SynchronizationException if updating link fails
  */
 void update() throws SynchronizationException {
   if (_id == null) {
     throw new SynchronizationException("Attempt to update non-existent link");
   }
   JsonValue jv = toJsonValue();
   try {
     UpdateRequest r = Requests.newUpdateRequest(linkId(_id), jv);
     r.setRevision(_rev);
     Resource resource =
         mapping
             .getService()
             .getConnectionFactory()
             .getConnection()
             .update(mapping.getService().getServerContext(), r);
     _rev = resource.getRevision();
   } catch (ResourceException ose) {
     LOGGER.warn("Failed to update link", ose);
     throw new SynchronizationException(ose);
   }
 }
Example #3
0
  /** {@inheritDoc} */
  @Override
  public void updateInstance(
      final ServerContext context,
      final String resourceId,
      final UpdateRequest request,
      final ResultHandler<Resource> handler) {

    RealmContext realmContext = context.asContext(RealmContext.class);
    String realmPath = realmContext.getResolvedRealm();

    final JsonValue realmDetails = request.getContent();
    Resource resource;
    String realm = null;
    OrganizationConfigManager ocm;
    OrganizationConfigManager realmCreatedOcm;

    String principalName = PrincipalRestUtils.getPrincipalNameFromServerContext(context);

    try {

      hasPermission(context);
      realm = checkForTopLevelRealm(resourceId);
      if (realm != null && !realm.startsWith("/")) {
        realm = "/" + realm;
      }
      if (!realmPath.equalsIgnoreCase("/")) {
        realm = realmPath + realm;
      }
      // The initial attempt to UPDATE a realm,
      // if the realm does not exist it must be created
      ocm = new OrganizationConfigManager(getSSOToken(), realm);
      List newServiceNames;
      // update ID_REPO attributes
      updateConfiguredServices(ocm, createServicesMap(realmDetails));
      newServiceNames = realmDetails.get(SERVICE_NAMES).asList();
      if (newServiceNames == null || newServiceNames.isEmpty()) {
        debug.error("RealmResource.updateInstance() : No Services defined.");
      } else {
        assignServices(ocm, newServiceNames); // assign services to realm
      }
      // READ THE REALM
      realmCreatedOcm = new OrganizationConfigManager(getSSOToken(), realm);

      debug.message(
          "RealmResource.updateInstance :: UPDATE of realm "
              + realm
              + " performed by "
              + principalName);

      // create a resource for handler to return
      resource =
          new Resource(
              realm,
              String.valueOf(System.currentTimeMillis()),
              createJsonMessage("realmUpdated", realmCreatedOcm.getOrganizationName()));
      handler.handleResult(resource);
    } catch (SMSException e) {
      try {
        configureErrorMessage(e);
      } catch (NotFoundException nfe) {
        if (debug.errorEnabled()) {
          debug.error(
              "RealmResource.updateInstance()"
                  + "Cannot find "
                  + resourceId
                  + ":"
                  + e
                  + "\n"
                  + "CREATING "
                  + resourceId);
        }
        // Realm was NOT found, therefore create the realm
        try {
          String parentRealm = RealmUtils.getParentRealm(realm);
          String childRealm = RealmUtils.getChildRealm(realm);
          ocm = new OrganizationConfigManager(getSSOToken(), parentRealm);
          // create the realm
          createOrganization(ocm, realmDetails, childRealm, realmPath);

          // read the realm to make sure that it has been created...
          realmCreatedOcm = new OrganizationConfigManager(getSSOToken(), realm);

          if (debug.messageEnabled()) {
            debug.message(
                "RealmResource.updateInstance :: UPDATE of realm "
                    + realm
                    + " performed by "
                    + principalName);
          }

          resource =
              new Resource(
                  childRealm,
                  String.valueOf(System.currentTimeMillis()),
                  createJsonMessage("realmCreated", realmCreatedOcm.getOrganizationName()));
          if (debug.messageEnabled()) {
            debug.message("RealmResource :: UPDATE : Updated resource with ID, " + resourceId);
          }
          handler.handleResult(resource);
        } catch (SMSException smse) {

          debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, smse);

          try {
            configureErrorMessage(smse);
          } catch (NotFoundException nf) {
            debug.error("RealmResource.updateInstance() : Cannot find " + resourceId, nf);
            handler.handleError(nf);
          } catch (ForbiddenException fe) {
            // User does not have authorization
            debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, fe);
            handler.handleError(fe);
          } catch (PermanentException pe) {
            debug.error("RealmResource.updateInstance() Cannot UPDATE " + resourceId, pe);
            // Cannot recover from this exception
            handler.handleError(pe);
          } catch (ConflictException ce) {
            debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, ce);
            handler.handleError(ce);
          } catch (BadRequestException be) {
            debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, be);
            handler.handleError(be);
          }
        } catch (Exception ex) {
          debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, ex);
          handler.handleError(new NotFoundException("Cannot update realm.", ex));
        }

      } catch (ForbiddenException fe) {
        // User does not have authorization
        debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, fe);
        handler.handleError(fe);
      } catch (PermanentException pe) {
        debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, pe);
        // Cannot recover from this exception
        handler.handleError(pe);
      } catch (ConflictException ce) {
        debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, ce);
        handler.handleError(ce);
      } catch (BadRequestException be) {
        debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, be);
        handler.handleError(be);
      } catch (Exception ex) {
        debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, ex);
        handler.handleError(new NotFoundException("Cannot update realm.", ex));
      }
    } catch (SSOException sso) {
      debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, sso);
      handler.handleError(new PermanentException(401, "Access Denied", null));
    } catch (ForbiddenException fe) {
      debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, fe);
      handler.handleError(fe);
    } catch (PermanentException pe) {
      debug.error("RealmResource.Instance() : Cannot UPDATE " + resourceId, pe);
      // Cannot recover from this exception
      handler.handleError(pe);
    } catch (Exception ex) {
      debug.error("RealmResource.updateInstance() : Cannot UPDATE " + resourceId, ex);
      handler.handleError(new NotFoundException("Cannot update realm.", ex));
    }
  }
  /**
   * Updates the specified object in the object set.
   *
   * <p>This implementation does not require MVCC and uses the current revision if no revision is
   * specified in the request.
   *
   * <p>If successful, this method updates metadata properties within the passed object, including:
   * a new {@code _rev} value for the revised object's version
   *
   * @param request the contents of the object to update
   * @throws ConflictException if version is required but is {@code null}.
   * @throws ForbiddenException if access to the object is forbidden.
   * @throws NotFoundException if the specified object could not be found.
   * @throws PreconditionFailedException if version did not match the existing object in the set.
   * @throws BadRequestException if the passed identifier is invalid
   */
  @Override
  public ResourceResponse update(UpdateRequest request) throws ResourceException {
    if (request.getResourcePathObject().size() < 2) {
      throw new NotFoundException(
          "The object identifier did not include sufficient information to determine the object type and identifier of the object to update: "
              + request.getResourcePath());
    }

    final String type = request.getResourcePathObject().parent().toString();
    final String localId = request.getResourcePathObject().leaf();

    String orientClassName = typeToOrientClassName(type);
    JsonValue obj = request.getContent();

    if (request.getRevision() != null && !"".equals(request.getRevision())) {
      obj.put(DocumentUtil.TAG_REV, request.getRevision());
    }

    ODatabaseDocumentTx db = getConnection();
    try {
      ODocument existingDoc = predefinedQueries.getByID(localId, type, db);
      if (existingDoc == null) {
        throw new NotFoundException(
            "Update on object " + request.getResourcePath() + " could not find existing object.");
      }
      ODocument updatedDoc = DocumentUtil.toDocument(obj, existingDoc, db, orientClassName);
      logger.trace("Updated doc for id {} to save {}", request.getResourcePath(), updatedDoc);

      updatedDoc.save();

      obj.put(DocumentUtil.TAG_REV, Integer.toString(updatedDoc.getVersion()));
      // Set ID to return to caller
      obj.put(DocumentUtil.TAG_ID, updatedDoc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY));
      logger.debug(
          "Committed update for id: {} revision: {}",
          request.getResourcePath(),
          updatedDoc.getVersion());
      logger.trace("Update payload for id: {} doc: {}", request.getResourcePath(), updatedDoc);
      return newResourceResponse(
          obj.get(DocumentUtil.TAG_ID).asString(), obj.get(DocumentUtil.TAG_REV).asString(), obj);
    } catch (ODatabaseException ex) {
      // Without transaction the concurrent modification exception gets nested instead
      if (isCauseConcurrentModificationException(ex, 10)) {
        throw new PreconditionFailedException(
            "Update rejected as current Object revision is different than expected by caller, the object has changed since retrieval: "
                + ex.getMessage(),
            ex);
      } else {
        throw ex;
      }
    } catch (OConcurrentModificationException ex) {
      throw new PreconditionFailedException(
          "Update rejected as current Object revision is different than expected by caller, the object has changed since retrieval: "
              + ex.getMessage(),
          ex);
    } catch (RuntimeException e) {
      throw e;
    } finally {
      if (db != null) {
        db.close();
      }
    }
  }
  void doPut(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);

      if (req.getHeader(HEADER_IF_MATCH) != null && req.getHeader(HEADER_IF_NONE_MATCH) != null) {
        // FIXME: i18n
        throw new PreconditionFailedException(
            "Simultaneous use of If-Match and If-None-Match not " + "supported for PUT requests");
      }

      final Map<String, String[]> parameters = req.getParameterMap();
      final JsonValue content = getJsonContent(req);

      final String rev = getIfNoneMatch(req);
      if (ETAG_ANY.equals(rev)) {
        // This is a create with a user provided resource ID: split the
        // path into the parent resource name and resource ID.
        final String resourceName = getResourceName(req);
        final int i = resourceName.lastIndexOf('/');
        final CreateRequest request;
        if (resourceName.isEmpty()) {
          // FIXME: i18n.
          throw new BadRequestException("No new resource ID in HTTP PUT request");
        } else if (i < 0) {
          // We have a pathInfo of the form "{id}"
          request = Requests.newCreateRequest(EMPTY_STRING, content);
          request.setNewResourceId(resourceName);
        } else {
          // We have a pathInfo of the form "{container}/{id}"
          request = Requests.newCreateRequest(resourceName.substring(0, i), content);
          request.setNewResourceId(resourceName.substring(i + 1));
        }
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else if (parseCommonParameter(name, values, request)) {
            continue;
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      } else {
        final UpdateRequest request =
            Requests.newUpdateRequest(getResourceName(req), content).setRevision(getIfMatch(req));
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else if (parseCommonParameter(name, values, request)) {
            continue;
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }
  /**
   * Stores the <code>Dictionary</code> under the given <code>pid</code>.
   *
   * @param pid The identifier of the dictionary.
   * @param properties The <code>Dictionary</code> to store.
   * @throws IOException If an error occurrs storing the dictionary. If this exception is thrown, it
   *     is expected, that {@link #exists(String) exists(pid} returns <code>false</code>.
   */
  public void store(String pid, Dictionary properties) throws IOException {
    logger.debug("Store call for {} {}", pid, properties);

    // Store config handling settings in memory
    if (pid.startsWith("org.apache.felix.fileinstall")) {
      tempStore.put(pid, properties);
      return;
    }

    try {
      if (isReady(0) && requireRepository) {
        String id = pidToId(pid);

        Map<String, Object> obj = dictToMap(properties);
        JsonValue content = new JsonValue(obj);
        String configResourceId =
            ConfigBootstrapHelper.getId(
                content.get(ConfigBootstrapHelper.CONFIG_ALIAS).asString(),
                content.get(ConfigBootstrapHelper.SERVICE_PID).asString(),
                content.get(ConfigBootstrapHelper.SERVICE_FACTORY_PID).asString());
        String configString = (String) obj.get(JSONEnhancedConfig.JSON_CONFIG_PROPERTY);
        Map<Object, Object> configMap = deserializeConfig(configString);
        if (configMap != null) {
          configMap.put("_id", configResourceId);
        }
        obj.put(JSONEnhancedConfig.JSON_CONFIG_PROPERTY, configMap);

        Map<String, Object> existing = null;
        try {
          ReadRequest readRequest = Requests.newReadRequest(id);
          existing = repo.read(readRequest).getContent().asMap();
        } catch (NotFoundException ex) {
          // Just detect that it doesn't exist
        }
        if (existing != null) {
          String rev = (String) existing.get("_rev");

          existing.remove("_rev");
          existing.remove("_id");
          obj.remove("_rev"); // beware, this means _id and _rev should not be in config file
          obj.remove("_id"); // beware, this means _id and _rev should not be in config file
          obj.remove(RepoPersistenceManager.BUNDLE_LOCATION);
          obj.remove(RepoPersistenceManager.FELIX_FILEINSTALL_FILENAME);
          if (!existing.equals(obj)) {
            logger.trace("Not matching {} {}", existing, obj);
            boolean retry;
            do {
              retry = false;
              try {
                UpdateRequest r = Requests.newUpdateRequest(id, new JsonValue(obj));
                r.setRevision(rev);
                repo.update(r);
              } catch (PreconditionFailedException ex) {
                logger.debug("Concurrent change during update, retrying {} {}", pid, rev);
                ReadRequest readRequest = Requests.newReadRequest(id);
                existing = repo.read(readRequest).getContent().asMap();
                retry = true;
              }
            } while (retry);
            logger.debug("Updated existing config {} {} {}", new Object[] {pid, rev, obj});
          } else {
            logger.debug(
                "Existing config same as store request, ignoring {} {} {}",
                new Object[] {pid, rev, obj});
          }
        } else {
          logger.trace("Creating: {} {} ", id, obj);
          // This may create a new (empty) configuration, which felix marks with
          // _felix___cm__newConfiguration=true
          String newResourceId = id.substring(CONFIG_CONTEXT_PREFIX.length());
          CreateRequest createRequest =
              Requests.newCreateRequest(CONFIG_CONTEXT_PREFIX, new JsonValue(obj));
          createRequest.setNewResourceId(newResourceId);
          obj = repo.create(createRequest).getContent().asMap();
          logger.debug("Stored new config in repository {} {}", pid, obj);
        }
      } else {
        tempStore.put(pid, properties);
        logger.debug("Stored in memory {} {}", pid, properties);
      }
    } catch (ResourceException ex) {
      throw new IOException("Failed to store configuration in repository: " + ex.getMessage(), ex);
    }
  }