/** * Queries relationships, returning the relationship associated with this providers resource path * and the specified relationship field. * * @param context The current context * @param managedObjectId The id of the managed object to find relationships associated with * @return */ private Promise<ResourceResponse, ResourceException> queryRelationship( final Context context, final String managedObjectId) { try { final QueryRequest queryRequest = Requests.newQueryRequest(REPO_RESOURCE_PATH); final List<ResourceResponse> relationships = new ArrayList<>(); queryRequest.setQueryFilter( QueryFilter.and( QueryFilter.equalTo( new JsonPointer(isReverse ? REPO_FIELD_SECOND_ID : REPO_FIELD_FIRST_ID), resourcePath.child(managedObjectId)), QueryFilter.equalTo(new JsonPointer(REPO_FIELD_FIRST_PROPERTY_NAME), propertyName))); connectionFactory.getConnection().query(context, queryRequest, relationships); if (relationships.isEmpty()) { return new NotFoundException().asPromise(); } else { // TODO OPENIDM-4094 - check size and throw illegal state if more than one? return newResultPromise(FORMAT_RESPONSE.apply(relationships.get(0))); } } catch (ResourceException e) { return e.asPromise(); } }
private boolean authenticate(Credential credential, SecurityContextMapper securityContextMapper) throws AuthException { if (!credential.isComplete()) { logger.debug("Failed authentication, missing or empty headers"); return false; } // set the authenticationId of the user that is trying to authenticate securityContextMapper.setAuthenticationId(credential.username); try { return authenticator.authenticate( credential.username, credential.password, authnFilterHelper.getRouter().createServerContext()); } catch (ResourceException e) { logger.debug( "Failed delegated authentication of {} on {}.", credential.username, queryOnResource, e); if (e.isServerError()) { // HTTP server-side error throw new JaspiAuthException( "Failed delegated authentication of " + credential.username + " on " + queryOnResource, e); } // authentication failed return false; } }
protected ResourceException convertScriptException(final ScriptException scriptException) { ResourceException convertedError; try { throw scriptException; } catch (ScriptThrownException e) { convertedError = e.toResourceException(ResourceException.INTERNAL_ERROR, scriptException.getMessage()); } catch (ScriptException e) { convertedError = new InternalServerErrorException(scriptException.getMessage(), scriptException); } if (convertedError.getDetail().isNull()) { convertedError.setDetail(new JsonValue(new HashMap<String, Object>())); } final JsonValue detail = convertedError.getDetail(); if (detail.get("fileName").isNull() && detail.get("lineNumber").isNull() && detail.get("columnNumber").isNull()) { detail.put("fileName", scriptException.getFileName()); detail.put("lineNumber", scriptException.getLineNumber()); detail.put("columnNumber", scriptException.getColumnNumber()); } return convertedError; }
/** {@inheritDoc} */ public Promise<ResourceResponse, ResourceException> readInstance( Context context, String resourceId, ReadRequest request) { final String realm = getRealm(context); debug.message("ServerInfoResource :: READ : in realm: " + realm); if (COOKIE_DOMAINS.equalsIgnoreCase(resourceId)) { return getCookieDomains(); } else if (ALL_SERVER_INFO.equalsIgnoreCase(resourceId)) { return getAllServerInfo(context, realm); } else { // for now this is the only case coming in, so fail if otherwise final ResourceException e = new NotSupportedException("ResourceId not supported: " + resourceId); if (debug.errorEnabled()) { debug.error( "ServerInfoResource :: READ : in realm: " + realm + ": Cannot receive information on requested resource: " + resourceId, e); } return e.asPromise(); } }
/** * Returns the <code>Dictionary</code> for the given <code>pid</code>. * * @param pid The identifier for the dictionary to load. * @return The dictionary for the identifier. This must not be <code>null</code> but may be empty. * @throws IOException If an error occurrs loading the dictionary. An <code>IOException</code> * must also be thrown if no dictionary exists for the given identifier. */ public Dictionary load(String pid) throws IOException { logger.debug("Config load call for {}", pid); Dictionary result = null; try { if (isReady(0) && requireRepository) { String id = pidToId(pid); ReadRequest readRequest = Requests.newReadRequest(id); Resource existing = repo.read(readRequest); Map<String, Object> existingConfig = existing.getContent().asMap(); Object configMap = existingConfig.get(JSONEnhancedConfig.JSON_CONFIG_PROPERTY); String configString = serializeConfig(configMap); existingConfig.put(JSONEnhancedConfig.JSON_CONFIG_PROPERTY, configString); logger.debug("Config loaded {} {}", pid, existing); result = mapToDict(existingConfig); } else if (!requireRepository) { result = tempStore.get(pid); if (result == null) { throw new IOException("No entry for " + pid + " exists."); } logger.debug("Config loaded from temporary store {} {}", pid, result); } } catch (NotFoundException ex) { result = tempStore.get(pid); if (result == null) { throw new IOException("No entry for " + pid + " exists."); } logger.debug("Config loaded from temporary store {} {}", pid, result); } catch (ResourceException ex) { throw new IOException("Failed to load configuration in repository: " + ex.getMessage(), ex); } return result; }
public Promise<ResourceResponse, ResourceException> handleUpdate( Context context, UpdateRequest request) { EventEntry measure = Publisher.start( Name.get( "openidm/internal/script/" + this.getScriptEntry().getName().getName() + "/update"), null, null); try { final ScriptEntry _scriptEntry = getScriptEntry(); if (!_scriptEntry.isActive()) { throw new ServiceUnavailableException("Inactive script: " + _scriptEntry.getName()); } final Script script = _scriptEntry.getScript(context); script.setBindings(script.createBindings()); customizer.handleUpdate(context, request, script.getBindings()); return evaluate(request, script); } catch (ScriptException e) { return convertScriptException(e).asPromise(); } catch (ResourceException e) { return e.asPromise(); } catch (Exception e) { return new InternalServerErrorException(e.getMessage(), e).asPromise(); } finally { measure.end(); } }
/** * Returns <code>true</code> if a persisted <code>Dictionary</code> exists for the given <code>pid * </code>. * * @param pid The identifier for the dictionary to test. */ public boolean exists(String pid) { logger.debug("Config exists call for {}", pid); boolean exists = false; if (isReady(0) && requireRepository) { String id = pidToId(pid); try { ReadRequest readRequest = Requests.newReadRequest(id); Resource existing = repo.read(readRequest); exists = (existing != null); } catch (NotFoundException ex) { exists = false; } catch (ResourceException ex) { throw new RuntimeException( "Failed to check if configuration exists in repository: " + ex.getMessage(), ex); } } if (!exists) { exists = tempStore.containsKey(pid); if (exists) { logger.debug("Entry exists in temporary store for '{}'", pid); } } else { logger.debug("Entry exists for '{}'", pid); } if (!exists) { logger.debug("Entry does not exist for '{}'", pid); } return exists; }
@Override public Promise<ResourceResponse, ResourceException> createInstance( Context context, CreateRequest request) { TokenGenerationServiceInvocationState invocationState; try { invocationState = TokenGenerationServiceInvocationState.fromJson(request.getContent()); } catch (Exception e) { logger.error( "Exception caught marshalling json into TokenGenerationServiceInvocationState instance: " + e); return new BadRequestException(e.getMessage(), e).asPromise(); } SSOToken subjectToken; try { subjectToken = validateAssertionSubjectSession(invocationState); } catch (ForbiddenException e) { return e.asPromise(); } STSInstanceState stsInstanceState; try { stsInstanceState = getSTSInstanceState(invocationState); } catch (ResourceException e) { return e.asPromise(); } if (TokenType.SAML2.equals(invocationState.getTokenType())) { try { final String assertion = saml2TokenGeneration.generate(subjectToken, stsInstanceState, invocationState); return newResultPromise(issuedTokenResource(assertion)); } catch (TokenCreationException e) { logger.error("Exception caught generating saml2 token: " + e, e); return e.asPromise(); } catch (Exception e) { logger.error("Exception caught generating saml2 token: " + e, e); return new InternalServerErrorException(e.toString(), e).asPromise(); } } else if (TokenType.OPENIDCONNECT.equals(invocationState.getTokenType())) { try { final String assertion = openIdConnectTokenGeneration.generate(subjectToken, stsInstanceState, invocationState); return newResultPromise(issuedTokenResource(assertion)); } catch (TokenCreationException e) { logger.error("Exception caught generating OpenIdConnect token: " + e, e); return e.asPromise(); } catch (Exception e) { logger.error("Exception caught generating OpenIdConnect token: " + e, e); return new InternalServerErrorException(e.toString(), e).asPromise(); } } else { String message = "Bad request: unexpected token type:" + invocationState.getTokenType(); logger.error(message); return new BadRequestException(message).asPromise(); } }
/** * Returns names of all realms included in the subtree rooted by the realm indicated in the query * url. * * <p>Names are unsorted and given as full paths. * * <p>Filtering, sorting, and paging of results is not supported. * * <p>{@inheritDoc} */ @Override public void queryCollection( final ServerContext context, final QueryRequest request, final QueryResultHandler handler) { final String principalName = PrincipalRestUtils.getPrincipalNameFromServerContext(context); final RealmContext realmContext = context.asContext(RealmContext.class); final String realmPath = realmContext.getResolvedRealm(); try { final SSOTokenManager mgr = SSOTokenManager.getInstance(); final SSOToken ssoToken = mgr.createSSOToken(getCookieFromServerContext(context)); final OrganizationConfigManager ocm = new OrganizationConfigManager(ssoToken, realmPath); final List<String> realmsInSubTree = new ArrayList<String>(); realmsInSubTree.add(realmPath); for (final Object subRealmRelativePath : ocm.getSubOrganizationNames("*", true)) { if (realmPath.endsWith("/")) { realmsInSubTree.add(realmPath + subRealmRelativePath); } else { realmsInSubTree.add(realmPath + "/" + subRealmRelativePath); } } debug.message("RealmResource :: QUERY : performed by " + principalName); for (final Object realmName : realmsInSubTree) { JsonValue val = new JsonValue(realmName); Resource resource = new Resource((String) realmName, "0", val); handler.handleResource(resource); } handler.handleResult(new QueryResult()); } catch (SSOException ex) { debug.error("RealmResource :: QUERY by " + principalName + " failed : " + ex); handler.handleError(ResourceException.getException(ResourceException.FORBIDDEN)); } catch (SMSException ex) { debug.error("RealmResource :: QUERY by " + principalName + " failed :" + ex); switch (ex.getExceptionCode()) { case STATUS_NO_PERMISSION: // This exception will be thrown if permission to read realms from SMS has not been // delegated handler.handleError(ResourceException.getException(ResourceException.FORBIDDEN)); break; default: handler.handleError(ResourceException.getException(ResourceException.INTERNAL_ERROR)); break; } } }
protected static void assertQueryPromiseFailedWithCodes( Promise<QueryResponse, ResourceException> promise, int resourceErrorCode, int entitlementErrorCode) { try { promise.getOrThrowUninterruptibly(); fail("Should throw ResourceException"); } catch (ResourceException e) { Assertions.assertThat(e.getCode()).isEqualTo(resourceErrorCode); Assertions.assertThat(e.getCause()).isInstanceOf(EntitlementException.class); Assertions.assertThat(((EntitlementException) e.getCause()).getErrorCode()) .isEqualTo(entitlementErrorCode); } }
/** {@inheritDoc} */ @Override public Promise<AuthorizationResult, ResourceException> authorizeCreate( Context context, CreateRequest request) { try { if (!getUserId(context).equalsIgnoreCase(getUserIdFromUri(context))) { return Promises.newResultPromise( AuthorizationResult.accessDenied( "Only resource owner of resource set can create UMA " + "policies for it.")); } else { return authorize(context); } } catch (ResourceException e) { return e.asPromise(); } }
/** * 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)); } }
/** * Calls buildAuditEvent() and invokes the request to the audit path. * * @param connectionFactory factory used to make crest call to audit service. */ public final Promise<ResourceResponse, ResourceException> log( ConfigAuditState configAuditState, Request request, Context context, ConnectionFactory connectionFactory) { try { JsonValue before = configAuditState.getBefore(); JsonValue after = configAuditState.getAfter(); // Get authenticationId from security context, if it exists. String authenticationId = (context.containsContext(SecurityContext.class)) ? context.asContext(SecurityContext.class).getAuthenticationId() : null; // Build the event utilizing the config builder. AuditEvent auditEvent = ConfigAuditEventBuilder.configEvent() .resourceOperationFromRequest(request) .authenticationFromSecurityContext(context) .runAs(authenticationId) .transactionIdFromRootContext(context) .revision(configAuditState.getRevision()) .timestamp(System.currentTimeMillis()) .eventName(CONFIG_AUDIT_EVENT_NAME) .before(null != before ? before.toString() : "") .after(null != after ? after.toString() : "") .changedFields(getChangedFields(before, after)) .toEvent(); return connectionFactory .getConnection() .create(context, Requests.newCreateRequest(AUDIT_CONFIG_REST_PATH, auditEvent.getValue())) .asPromise(); } catch (ResourceException e) { LOGGER.error("had trouble logging audit event for config changes.", e); return e.asPromise(); } catch (Exception e) { LOGGER.error("had trouble logging audit event for config changes.", e); return new InternalServerErrorException(e.getMessage(), e).asPromise(); } }
/** * Records an 'access' audit event before and after the filtered CREST resource receives an action * request. * * <p>If the 'before' audit event fails due to an error, the request is cancelled and an error * response is returned. If the 'after' audit event fails due to an error, the request is not * cancelled as it's affects may have already been applied. * * @param context {@inheritDoc} * @param request {@inheritDoc} * @param next {@inheritDoc} */ @Override public Promise<ActionResponse, ResourceException> filterAction( Context context, ActionRequest request, RequestHandler next) { final AuditingResultHandler auditingHandler = newAuditingResultHandler(context, request); try { auditingHandler.auditAccessAttempt(); } catch (AuditException e) { return newExceptionPromise(ResourceException.getException(ResourceException.INTERNAL_ERROR)); } return auditResponse(next.handleAction(context, request), auditingHandler); }
public Promise<ActionResponse, ResourceException> handleAction( final Context context, final ActionRequest request) { EventEntry measure = Publisher.start( Name.get( "openidm/internal/script/" + this.getScriptEntry().getName().getName() + "/action"), null, null); try { final ScriptEntry _scriptEntry = getScriptEntry(); if (!_scriptEntry.isActive()) { throw new ServiceUnavailableException("Inactive script: " + _scriptEntry.getName()); } final Script script = _scriptEntry.getScript(context); script.setBindings(script.createBindings()); customizer.handleAction(context, request, script.getBindings()); Object result = script.eval(); if (null == result) { return newActionResponse(new JsonValue(null)).asPromise(); } else if (result instanceof JsonValue) { return newActionResponse((JsonValue) result).asPromise(); } else if (result instanceof Map) { return newActionResponse(new JsonValue(result)).asPromise(); } else { JsonValue resource = new JsonValue(new HashMap<String, Object>(1)); resource.put("result", result); return newActionResponse(new JsonValue(result)).asPromise(); } } catch (ScriptException e) { return convertScriptException(e).asPromise(); } catch (ResourceException e) { return e.asPromise(); } catch (Exception e) { return new InternalServerErrorException(e.getMessage(), e).asPromise(); } finally { measure.end(); } }
@Override public Promise<ActionResponse, ResourceException> handleAction( final Context context, final ActionRequest request) { try { Map<String, String> params = request.getAdditionalParameters(); switch (request.getActionAsEnum(Action.class)) { case updateDbCredentials: String newUser = params.get("user"); String newPassword = params.get("password"); if (newUser == null || newPassword == null) { return adapt(new BadRequestException("Expecting 'user' and 'password' parameters")) .asPromise(); } synchronized (dbLock) { DBHelper.updateDbCredentials(dbURL, user, password, newUser, newPassword); JsonValue config = connectionFactory .getConnection() .read(context, Requests.newReadRequest("config", PID)) .getContent(); config.put("user", newUser); config.put("password", newPassword); UpdateRequest updateRequest = Requests.newUpdateRequest("config/" + PID, config); connectionFactory.getConnection().update(context, updateRequest); return newActionResponse(new JsonValue(params)).asPromise(); } case command: return newActionResponse(new JsonValue(command(request))).asPromise(); default: return adapt(new BadRequestException("Unknown action: " + request.getAction())) .asPromise(); } } catch (IllegalArgumentException e) { return adapt(new BadRequestException("Unknown action: " + request.getAction())).asPromise(); } catch (ResourceException e) { return e.asPromise(); } }
/** * Removes the <code>Dictionary</code> for the given <code>pid</code>. If such a dictionary does * not exist, this method has no effect. * * @param pid The identifier of the dictionary to delet. * @throws IOException If an error occurrs deleting the dictionary. This exception must not be * thrown if no dictionary with the given identifier exists. */ public void delete(String pid) throws IOException { logger.debug("delete call for {}", pid); Object removed = tempStore.remove(pid); if (removed != null) { logger.debug("Deleted {} from temporary store", pid); } try { if (isReady(0) && requireRepository) { String id = pidToId(pid); boolean retry; String rev = null; do { retry = false; try { ReadRequest readRequest = Requests.newReadRequest(id); Map<String, Object> existing = repo.read(readRequest).getContent().asMap(); if (existing != null) { rev = (String) existing.get("_rev"); DeleteRequest r = Requests.newDeleteRequest(id); r.setRevision(rev); repo.delete(r); logger.debug("Deleted {}", pid); } } catch (PreconditionFailedException ex) { logger.debug("Concurrent change during delete, retrying {} {}", pid, rev); retry = true; } catch (NotFoundException ex) { // If it doesn't exists (anymore) that's fine } } while (retry); } } catch (ResourceException ex) { throw new IOException( "Failed to delete configuration + " + pid + " in repository: " + ex.getMessage(), ex); } }
@Test public void getShouldFailWhenResourceExceptionThrown() throws ResourceException { // Given final String uri = "URI"; final Map<String, String> queryParameters = new HashMap<String, String>(); final Map<String, String> headers = new HashMap<String, String>(); final org.restlet.resource.ResourceException exception = new org.restlet.resource.ResourceException(500, "EXCEPTION_MESSAGE", "DESCRIPTION", "URI"); doThrow(exception).when(resource).get(JSONObject.class); // When try { restClient.get(uri, queryParameters, headers); } catch (ResourceException e) { // Then assertEquals(e.getCode(), 500); assertEquals(e.getMessage(), "EXCEPTION_MESSAGE"); verify(resource, never()).addQueryParameter(anyString(), anyString()); verify(requestHeaders, never()).set(anyString(), anyString()); verify(resource, never()).getContext(); } }
/** * Adapts a {@code Throwable} to a {@code ResourceException}. If the {@code Throwable} is an JSON * {@code JsonValueException} then an appropriate {@code ResourceException} is returned, otherwise * an {@code InternalServerErrorException} is returned. * * @param t The {@code Throwable} to be converted. * @return The equivalent resource exception. */ public ResourceException adapt(final Throwable t) { int resourceResultCode; try { throw t; } catch (OConcurrentModificationException ex) { resourceResultCode = ResourceException.VERSION_MISMATCH; } catch (final ResourceException e) { return e; } catch (final JsonValueException e) { resourceResultCode = ResourceException.BAD_REQUEST; } catch (final Throwable tmp) { resourceResultCode = ResourceException.INTERNAL_ERROR; } return ResourceException.getException(resourceResultCode, t.getMessage(), t); }
/** * Records an 'access' audit event before and after the filtered CREST resource receives an query * request. * * <p>If the 'before' audit event fails due to an error, the request is cancelled and an error * response is returned. If the 'after' audit event fails due to an error, the request is not * cancelled as it's affects may have already been applied. * * @param context {@inheritDoc} * @param request {@inheritDoc} * @param handler {@inheritDoc} * @param next {@inheritDoc} */ @Override public void filterQuery( ServerContext context, QueryRequest request, QueryResultHandler handler, RequestHandler next) { AuditingQueryResultHandler auditingHandler = newQueryAuditingResultHandler(context, request, handler); try { auditingHandler.auditAccessAttempt(); } catch (AuditException e) { handler.handleError(ResourceException.getException(ResourceException.INTERNAL_ERROR)); return; } next.handleQuery(context, request, auditingHandler); }
/** * Records an 'access' audit event before and after the filtered CREST resource receives an action * request. * * <p>If the 'before' audit event fails due to an error, the request is cancelled and an error * response is returned. If the 'after' audit event fails due to an error, the request is not * cancelled as it's affects may have already been applied. * * @param context {@inheritDoc} * @param request {@inheritDoc} * @param handler {@inheritDoc} * @param next {@inheritDoc} */ @Override public void filterAction( ServerContext context, ActionRequest request, ResultHandler<JsonValue> handler, RequestHandler next) { AuditingResultHandler<JsonValue> auditingHandler = newAuditingResultHandler(context, request, handler); try { auditingHandler.auditAccessAttempt(); } catch (AuditException e) { handler.handleError(ResourceException.getException(ResourceException.INTERNAL_ERROR)); return; } next.handleAction(context, request, auditingHandler); }
/** * 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); } }
/** * Performs the query on the specified object and returns the associated results. * * <p>Queries are parametric; a set of named parameters is provided as the query criteria. The * query result is a JSON object structure composed of basic Java types. * * <p>The returned map is structured as follow: - The top level map contains meta-data about the * query, plus an entry with the actual result records. - The <code>QueryConstants</code> defines * the map keys, including the result records (QUERY_RESULT) * * @param context identifies the object to query. * @param request the parameters of the query to perform. * @return the query results, which includes meta-data and the result records in JSON object * structure format. * @throws NotFoundException if the specified object could not be found. * @throws BadRequestException if the specified params contain invalid arguments, e.g. a query id * that is not configured, a query expression that is invalid, or missing query substitution * tokens. * @throws ForbiddenException if access to the object or specified query is forbidden. */ @Override public Promise<QueryResponse, ResourceException> handleQuery( final Context context, final QueryRequest request, final QueryResourceHandler handler) { // If paged results are requested then decode the cookie in order to determine // the index of the first result to be returned. final int requestPageSize = request.getPageSize(); // Cookie containing offset of last request final String pagedResultsCookie = request.getPagedResultsCookie(); final boolean pagedResultsRequested = requestPageSize > 0; // index of first record (used for SKIP/OFFSET) final int firstResultIndex; if (pagedResultsRequested) { if (StringUtils.isNotEmpty(pagedResultsCookie)) { try { firstResultIndex = Integer.parseInt(pagedResultsCookie); } catch (final NumberFormatException e) { return new BadRequestException("Invalid paged results cookie").asPromise(); } } else { firstResultIndex = Math.max(0, request.getPagedResultsOffset()); } } else { firstResultIndex = 0; } // Once cookie is processed Queries.query() can rely on the offset. request.setPagedResultsOffset(firstResultIndex); try { List<ResourceResponse> results = query(request); for (ResourceResponse result : results) { handler.handleResource(result); } /* * Execute additional -count query if we are paging */ final String nextCookie; // The number of results (if known) final int resultCount; if (pagedResultsRequested) { // count if requested switch (request.getTotalPagedResultsPolicy()) { case ESTIMATE: case EXACT: // Get total if -count query is available final String countQueryId = request.getQueryId() + "-count"; if (queries.queryIdExists(countQueryId)) { QueryRequest countRequest = Requests.copyOfQueryRequest(request); countRequest.setQueryId(countQueryId); // Strip pagination parameters countRequest.setPageSize(0); countRequest.setPagedResultsOffset(0); countRequest.setPagedResultsCookie(null); List<ResourceResponse> countResult = query(countRequest); if (countResult != null && !countResult.isEmpty()) { resultCount = countResult.get(0).getContent().get("total").asInteger(); } else { logger.debug("Count query {} failed.", countQueryId); resultCount = NO_COUNT; } } else { logger.debug("No count query found with id {}", countQueryId); resultCount = NO_COUNT; } break; case NONE: default: resultCount = NO_COUNT; break; } if (results.size() < requestPageSize) { nextCookie = null; } else { final int remainingResults = resultCount - (firstResultIndex + results.size()); if (remainingResults == 0) { nextCookie = null; } else { nextCookie = String.valueOf(firstResultIndex + requestPageSize); } } } else { resultCount = NO_COUNT; nextCookie = null; } if (resultCount == NO_COUNT) { return newQueryResponse(nextCookie).asPromise(); } else { return newQueryResponse(nextCookie, EXACT, resultCount).asPromise(); } } catch (ResourceException e) { return e.asPromise(); } }
/** * TODO Implement this method * * <p>{@inheritDoc} */ public Promise<QueryResponse, ResourceException> handleQuery( final Context context, final QueryRequest request, final QueryResourceHandler handler) { EventEntry measure = Publisher.start( Name.get( "openidm/internal/script/" + this.getScriptEntry().getName().getName() + "/query"), null, null); try { final ScriptEntry _scriptEntry = getScriptEntry(); if (!_scriptEntry.isActive()) { throw new ServiceUnavailableException("Inactive script: " + _scriptEntry.getName()); } final Script script = _scriptEntry.getScript(context); script.setBindings(script.createBindings()); customizer.handleQuery(context, request, script.getBindings()); final Function<Void> queryCallback = new Function<Void>() { @Override public Void call(Parameter scope, Function<?> callback, Object... arguments) throws ResourceException, NoSuchMethodException { if (arguments.length == 3 && null != arguments[2]) { if (arguments[2] instanceof Map) {} if (arguments[2] instanceof JsonValue) { } else { throw new NoSuchMethodException( FunctionFactory.getNoSuchMethodMessage("callback", arguments)); } } else if (arguments.length >= 2 && null != arguments[1]) { if (arguments[1] instanceof Map) {} if (arguments[1] instanceof JsonValue) { } else { throw new NoSuchMethodException( FunctionFactory.getNoSuchMethodMessage("callback", arguments)); } } else if (arguments.length >= 1 && null != arguments[0]) { if (arguments[0] instanceof Map) {} if (arguments[0] instanceof JsonValue) { } else { throw new NoSuchMethodException( FunctionFactory.getNoSuchMethodMessage("callback", arguments)); } } else { throw new NoSuchMethodException( FunctionFactory.getNoSuchMethodMessage("callback", arguments)); } return null; } }; script.putSafe("callback", queryCallback); Object rawResult = script.eval(); JsonValue result = null; if (rawResult instanceof JsonValue) { result = (JsonValue) rawResult; } else { result = new JsonValue(rawResult); } QueryResponse queryResponse = newQueryResponse(); // Script can either // - return null and instead use callback hook to call // handleResource, handleResult, handleError // careful! script MUST call handleResult or handleError itself // or // - return a result list of resources // or // - return a full query result structure if (!result.isNull()) { if (result.isList()) { // Script may return just the result elements as a list handleQueryResultList(result, handler); } else { // Or script may return a full query response structure, // with meta-data and results field if (result.isDefined(QueryResponse.FIELD_RESULT)) { handleQueryResultList(result.get(QueryResponse.FIELD_RESULT), handler); queryResponse = newQueryResponse( result.get(QueryResponse.FIELD_PAGED_RESULTS_COOKIE).asString(), result .get(QueryResponse.FIELD_TOTAL_PAGED_RESULTS_POLICY) .asEnum(CountPolicy.class), result.get(QueryResponse.FIELD_TOTAL_PAGED_RESULTS).asInteger()); } else { logger.debug("Script returned unexpected query result structure: ", result.getObject()); return new InternalServerErrorException( "Script returned unexpected query result structure of type " + result.getObject().getClass()) .asPromise(); } } } return queryResponse.asPromise(); } catch (ScriptException e) { return convertScriptException(e).asPromise(); } catch (ResourceException e) { return e.asPromise(); } catch (Exception e) { return new InternalServerErrorException(e.getMessage(), e).asPromise(); } finally { measure.end(); } }
@Override public void updateInstance( ServerContext context, UpdateRequest request, ResultHandler<Resource> handler) { handler.handleError(ResourceException.getException(ResourceException.NOT_SUPPORTED)); }
@Override public void actionInstance( ServerContext context, ActionRequest request, ResultHandler<JsonValue> handler) { handler.handleError(ResourceException.getException(ResourceException.NOT_SUPPORTED)); }