/** * 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; }
@Test public void crestReadIsAllowed() throws SSOException, DelegationException { // Given... final Set<String> actions = new HashSet<>(Arrays.asList("READ")); final DelegationPermission permission = new DelegationPermission( "/abc", "rest", "1.0", "policies", "read", actions, EXTENSIONS, DUMB_FUNC); given(factory.newInstance("/abc", "rest", "1.0", "policies", "read", actions, EXTENSIONS)) .willReturn(permission); given(subjectContext.getCallerSSOToken()).willReturn(token); given(evaluator.isAllowed(token, permission, ENVIRONMENT)).willReturn(true); JsonValue jsonValue = json(object(field("someKey", "someValue"))); Promise<ResourceResponse, ResourceException> promise = Promises.newResultPromise(Responses.newResourceResponse("1", "1.0", jsonValue)); given(provider.readInstance(isA(Context.class), eq("123"), isA(ReadRequest.class))) .willReturn(promise); // When... final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module); final Router router = new Router(); router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain); final RealmContext context = new RealmContext(subjectContext); final ReadRequest request = Requests.newReadRequest("/policies/123"); context.setSubRealm("abc", "abc"); Promise<ResourceResponse, ResourceException> result = router.handleRead(context, request); // Then... assertThat(result).succeeded().withContent().stringAt("someKey").isEqualTo("someValue"); }
/** * 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; }
@Test public void testReadSchedule() throws Exception { // given final ReadRequest readRequest = Requests.newReadRequest("test1"); // when Promise<ResourceResponse, ResourceException> promise = schedulerService.handleRead(new RootContext(), readRequest); // then AssertJPromiseAssert.assertThat(promise).isNotNull().succeeded(); ResourceResponse resourceResponse = promise.getOrThrow(); assertThat(resourceResponse.getContent().asMap()).isEqualTo(testScheduleConfig.asMap()); }
@Test public void testResource() throws Exception { ScriptName scriptName = new ScriptName("resource", getLanguageName()); ScriptEntry scriptEntry = getScriptRegistry().takeScript(scriptName); Assert.assertNotNull(scriptEntry); Script script = scriptEntry.getScript(new RootContext()); // Set RequestLevel Scope script.put("ketto", 2); script.putSafe("callback", mock(Function.class)); JsonValue createContent = new JsonValue(new LinkedHashMap<String, Object>()); createContent.put("externalId", "701984"); createContent.put("userName", "*****@*****.**"); createContent.put( "assignedDashboard", Arrays.asList("Salesforce", "Google", "ConstantContact")); createContent.put("displayName", "Babs Jensen"); createContent.put("nickName", "Babs"); JsonValue updateContent = createContent.copy(); updateContent.put("_id", UUID.randomUUID().toString()); updateContent.put("profileUrl", "https://login.example.com/bjensen"); final Context context = new ApiInfoContext( new SecurityContext(new RootContext(), "*****@*****.**", null), "", ""); script.put("context", context); CreateRequest createRequest = Requests.newCreateRequest("/Users", "701984", createContent); script.put("createRequest", createRequest); ReadRequest readRequest = Requests.newReadRequest("/Users/701984"); script.put("readRequest", readRequest); UpdateRequest updateRequest = Requests.newUpdateRequest("/Users/701984", updateContent); script.put("updateRequest", updateRequest); PatchRequest patchRequest = Requests.newPatchRequest("/Users/701984", PatchOperation.replace("userName", "ddoe")); script.put("patchRequest", patchRequest); QueryRequest queryRequest = Requests.newQueryRequest("/Users/"); script.put("queryRequest", queryRequest); DeleteRequest deleteRequest = Requests.newDeleteRequest("/Users/701984"); script.put("deleteRequest", deleteRequest); ActionRequest actionRequest = Requests.newActionRequest("/Users", "clear"); script.put("actionRequest", actionRequest); script.eval(); }
@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); } }
void doGet(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); rejectIfMatch(req); final Map<String, String[]> parameters = req.getParameterMap(); if (hasParameter(req, PARAM_QUERY_ID) || hasParameter(req, PARAM_QUERY_EXPRESSION) || hasParameter(req, PARAM_QUERY_FILTER)) { // Additional pre-validation for queries. rejectIfNoneMatch(req); // Query against collection. final QueryRequest request = Requests.newQueryRequest(getResourceName(req)); for (final Map.Entry<String, String[]> p : parameters.entrySet()) { final String name = p.getKey(); final String[] values = p.getValue(); if (parseCommonParameter(name, values, request)) { continue; } else if (name.equalsIgnoreCase(PARAM_SORT_KEYS)) { for (final String s : values) { try { request.addSortKey(s.split(SORT_KEYS_DELIMITER)); } catch (final IllegalArgumentException e) { // FIXME: i18n. throw new BadRequestException( "The value '" + s + "' for parameter '" + name + "' could not be parsed as a comma " + "separated list of sort keys"); } } } else if (name.equalsIgnoreCase(PARAM_QUERY_ID)) { request.setQueryId(asSingleValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_QUERY_EXPRESSION)) { request.setQueryExpression(asSingleValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_COOKIE)) { request.setPagedResultsCookie(asSingleValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_OFFSET)) { request.setPagedResultsOffset(asIntValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_PAGE_SIZE)) { request.setPageSize(asIntValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_QUERY_FILTER)) { final String s = asSingleValue(name, values); try { request.setQueryFilter(QueryFilter.valueOf(s)); } catch (final IllegalArgumentException e) { // FIXME: i18n. throw new BadRequestException( "The value '" + s + "' for parameter '" + name + "' could not be parsed as a valid query filter"); } } else { request.setAdditionalParameter(name, asSingleValue(name, values)); } } // Check for incompatible arguments. if (request.getQueryId() != null && request.getQueryFilter() != null) { // FIXME: i18n. throw new BadRequestException( "The parameters " + PARAM_QUERY_ID + " and " + PARAM_QUERY_FILTER + " are mutually exclusive"); } if (request.getQueryId() != null && request.getQueryExpression() != null) { // FIXME: i18n. throw new BadRequestException( "The parameters " + PARAM_QUERY_ID + " and " + PARAM_QUERY_EXPRESSION + " are mutually exclusive"); } if (request.getQueryFilter() != null && request.getQueryExpression() != null) { // FIXME: i18n. throw new BadRequestException( "The parameters " + PARAM_QUERY_FILTER + " and " + PARAM_QUERY_EXPRESSION + " are mutually exclusive"); } doRequest(req, resp, acceptVersion, request); } else { // Read of instance within collection or singleton. final String rev = getIfNoneMatch(req); if (ETAG_ANY.equals(rev)) { // FIXME: i18n throw new PreconditionFailedException( "If-None-Match * not appropriate for " + getMethod(req) + " requests"); } final ReadRequest request = Requests.newReadRequest(getResourceName(req)); for (final Map.Entry<String, String[]> p : parameters.entrySet()) { final String name = p.getKey(); final String[] values = p.getValue(); if (parseCommonParameter(name, values, request)) { continue; } else if (PARAM_MIME_TYPE.equalsIgnoreCase(name)) { if (values.length != 1 || values[0].split(FIELDS_DELIMITER).length > 1) { // FIXME: i18n. throw new BadRequestException("Only one mime type value allowed"); } if (parameters.get(PARAM_FIELDS).length != 1) { // FIXME: i18n. throw new BadRequestException( "The mime type parameter requires only 1 field to be specified"); } } 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); } }