Skip to content

Commit

Permalink
Add support for specifying formatter config (#235)
Browse files Browse the repository at this point in the history
Signed-off-by: Felix Zheng <felix.zheng@mongodb.com>
  • Loading branch information
felixzheng98 authored Oct 16, 2024
1 parent 0acff8a commit 80f8077
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.cedarpolicy.loader.LibraryLoader;
import com.cedarpolicy.model.exception.InternalException;
import com.cedarpolicy.model.formatter.Config;

public final class PolicyFormatter {

Expand All @@ -14,4 +15,7 @@ private PolicyFormatter() {

public static native String policiesStrToPretty(String policies)
throws InternalException, NullPointerException;

public static native String policiesStrToPrettyWithConfig(String policies, Config config)
throws InternalException, NullPointerException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.cedarpolicy.model.formatter;

public class Config {

private final int lineWidth;
private final int indentWidth;

public Config(int lineWidth, int indentWidth) {
this.lineWidth = lineWidth;
this.indentWidth = indentWidth;
}

@SuppressWarnings("unused")
public int getLineWidth() {
return lineWidth;
}

@SuppressWarnings("unused")
public int getIndentWidth() {
return indentWidth;
}
}
27 changes: 27 additions & 0 deletions CedarJava/src/test/java/com/cedarpolicy/PolicyFormatterTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.cedarpolicy.formatter.PolicyFormatter;
import com.cedarpolicy.model.exception.InternalException;
import com.cedarpolicy.model.formatter.Config;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -37,4 +38,30 @@ public void testPoliciesStrToPrettyMalformedCedarPolicy() throws Exception {
public void testPoliciesStrToPrettyNullSafety() {
assertThrows(NullPointerException.class, () -> PolicyFormatter.policiesStrToPretty(null));
}

@Test
public void testPoliciesStrToPrettyWithConfigNullSafety() throws Exception {
String cedarPolicy = Files.readString(Path.of(TEST_RESOURCES_DIR + "formatted_policy.cedar"));

assertThrows(NullPointerException.class,
() -> PolicyFormatter.policiesStrToPrettyWithConfig(null, null));

assertThrows(NullPointerException.class,
() -> PolicyFormatter.policiesStrToPrettyWithConfig(cedarPolicy, null));

assertThrows(NullPointerException.class,
() -> PolicyFormatter.policiesStrToPrettyWithConfig(null, new Config(120, 4)));
}

@Test
public void testPoliciesStrToPrettyWithConfig() throws Exception {
String unformattedCedarPolicy = Files.readString(
Path.of(TEST_RESOURCES_DIR + "unformatted_policy.cedar"));

String formattedCedarPolicyWithCustomConfig = Files.readString(
Path.of(TEST_RESOURCES_DIR + "formatted_policy_custom_config.cedar"));

assertEquals(formattedCedarPolicyWithCustomConfig,
PolicyFormatter.policiesStrToPrettyWithConfig(unformattedCedarPolicy, new Config(120, 4)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
permit (
principal,
action == Action::"update",
resource
)
when { resource.owner == principal };
2 changes: 1 addition & 1 deletion CedarJava/src/test/resources/malformed_policy_set.cedar
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ forbid (
principal == User::"Liam",
action,
resource = Photo::"Husky.jpg"
);
);
2 changes: 1 addition & 1 deletion CedarJava/src/test/resources/unformatted_policy.cedar
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ permit(
action
== Action::"update",
resource
) when {resource.owner == principal};
) when {resource.owner == principal};
25 changes: 22 additions & 3 deletions CedarJavaFFI/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use serde::{Deserialize, Serialize};
use serde_json::{from_str, Value};
use std::{error::Error, str::FromStr, thread};

use crate::objects::JFormatterConfig;
use crate::{
answer::Answer,
jset::Set,
Expand Down Expand Up @@ -537,7 +538,20 @@ pub fn policiesStrToPretty<'a>(
_: JClass,
policies_jstr: JString<'a>,
) -> jvalue {
match policies_str_to_pretty_internal(&mut env, policies_jstr) {
match policies_str_to_pretty_internal(&mut env, policies_jstr, None) {
Ok(v) => v.as_jni(),
Err(e) => jni_failed(&mut env, e.as_ref()),
}
}

#[jni_fn("com.cedarpolicy.formatter.PolicyFormatter")]
pub fn policiesStrToPrettyWithConfig<'a>(
mut env: JNIEnv<'a>,
_: JClass,
policies_jstr: JString<'a>,
config_obj: JObject<'a>,
) -> jvalue {
match policies_str_to_pretty_internal(&mut env, policies_jstr, Some(config_obj)) {
Ok(v) => v.as_jni(),
Err(e) => jni_failed(&mut env, e.as_ref()),
}
Expand All @@ -546,11 +560,16 @@ pub fn policiesStrToPretty<'a>(
fn policies_str_to_pretty_internal<'a>(
env: &mut JNIEnv<'a>,
policies_jstr: JString<'a>,
config_obj: Option<JObject<'a>>,
) -> Result<JValueOwned<'a>> {
if policies_jstr.is_null() {
if policies_jstr.is_null() || config_obj.as_ref().is_some_and(|obj| obj.is_null()) {
raise_npe(env)
} else {
let config = Config::default();
let config = if let Some(obj) = config_obj {
JFormatterConfig::cast(env, obj)?.get_rust_repr()
} else {
Config::default()
};
let policies_str = String::from(env.get_string(&policies_jstr)?);
match policies_str_to_pretty(&policies_str, &config) {
Ok(formatted_policies) => Ok(env.new_string(formatted_policies)?.into()),
Expand Down
34 changes: 34 additions & 0 deletions CedarJavaFFI/src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
use std::{marker::PhantomData, str::FromStr};

use cedar_policy::{EntityId, EntityTypeName, EntityUid};
use cedar_policy_formatter::Config;
use jni::{
objects::{JObject, JString, JValueGen, JValueOwned},
sys::jvalue,
Expand Down Expand Up @@ -368,3 +369,36 @@ impl<'a> AsRef<JObject<'a>> for JPolicy<'a> {
&self.obj
}
}

pub struct JFormatterConfig<'a> {
obj: JObject<'a>,
formatter_config: Config,
}

impl<'a> JFormatterConfig<'a> {
pub fn get_rust_repr(&self) -> Config {
self.formatter_config.clone()
}
}

impl<'a> AsRef<JObject<'a>> for JFormatterConfig<'a> {
fn as_ref(&self) -> &JObject<'a> {
&self.obj
}
}

impl<'a> Object<'a> for JFormatterConfig<'a> {
fn cast(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Result<Self> {
assert_is_class(env, &obj, "com/cedarpolicy/model/formatter/Config")?;
let line_width_jint = env.call_method(&obj, "getLineWidth", "()I", &[])?.i()?;
let indent_width_jint = env.call_method(&obj, "getIndentWidth", "()I", &[])?.i()?;
let formatter_config = Config {
line_width: usize::try_from(line_width_jint)?,
indent_width: isize::try_from(indent_width_jint)?,
};
Ok(Self {
obj,
formatter_config,
})
}
}

0 comments on commit 80f8077

Please sign in to comment.