Skip to content

Commit

Permalink
PoC for java records (JEP 395)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcurrie committed Jan 14, 2023
1 parent e2f3bde commit f8942c6
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 10 deletions.
6 changes: 3 additions & 3 deletions languages/java/oso/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<groupId>com.osohq</groupId>
<artifactId>oso</artifactId>
<!-- oso_version --><version>0.26.4</version>
<!-- oso_version --><version>0.26.5-SNAPSHOT</version>

<distributionManagement>
<snapshotRepository>
Expand All @@ -38,8 +38,8 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
Expand Down
24 changes: 17 additions & 7 deletions languages/java/oso/src/main/java/com/osohq/oso/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,7 @@ private void handleCall(
}
result = method.invoke(instance, args.get().toArray());
} else {
// Look for a field with the given name.
try {
Field field = cls.getField(attrName);
result = field.get(instance);
} catch (NoSuchFieldException f) {
throw new Exceptions.InvalidAttributeError(cls.getName(), attrName);
}
result = getFromFieldOrRecordAccessor(attrName, instance, cls);
}
String term = host.toPolarTerm(result).toString();
ffiQuery.callResult(callId, term);
Expand All @@ -141,6 +135,22 @@ private void handleCall(
}
}

private Object getFromFieldOrRecordAccessor(String attrName, Object instance, Class<?> cls) throws IllegalAccessException {
// Look for a field with the given name.
try {
Field field = cls.getField(attrName);
return field.get(instance);
} catch (NoSuchFieldException ignored) {
}
// Assume record so try the no args accessor method instead.
try {
Method method = cls.getMethod(attrName);
return method.invoke(instance);
} catch (NoSuchMethodException | InvocationTargetException e) {
throw new Exceptions.InvalidAttributeError(cls.getName(), attrName);
}
}

/** Helper for `NextExternal` query events */
private void handleNextExternal(long callId, JSONObject iterable) throws Exceptions.OsoException {
if (!calls.containsKey(callId)) {
Expand Down
155 changes: 155 additions & 0 deletions languages/java/oso/src/test/java/com/osohq/oso/OsoJavaRecordTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package com.osohq.oso;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

public class OsoJavaRecordTest {
protected Oso o;

public record User(String name) {
public List<Company> companies() {
return List.of(new Company(1));
}
}

public record Widget(int id) {
}

public record Company(int id) {

public String role(User a) {
if (a.name.equals("president")) {
return "admin";
}

return "guest";
}
}

@BeforeEach
public void setUp() throws Exception {
try {
URL testOso = getClass().getClassLoader().getResource("test_oso.polar");

o = new Oso();
o.registerClass(User.class, "User");
o.registerClass(Widget.class, "Widget");
o.registerClass(Company.class, "Company");

o.loadFile(testOso.getPath());
} catch (Exception e) {
throw new Error(e);
}
}

@Test
public void testIsAllowed() throws Exception {
User guest = new User("guest");
Widget resource1 = new Widget(1);
assertTrue(o.isAllowed(guest, "get", resource1));

User president = new User("president");
Company company = new Company(1);
assertTrue(o.isAllowed(president, "create", company));
}

@Test
public void testFail() throws Exception {
User guest = new User("guest");
Widget widget = new Widget(1);
assertFalse(o.isAllowed(guest, "not_allowed", widget));
}

@Test
public void testInstanceFromExternalCall() throws Exception {
Company company = new Company(1);
User guest = new User("guest");
assertTrue(o.isAllowed(guest, "frob", company));

// if the guest user can do it, then the dict should
// create an instance of the user and be allowed
HashMap<String, String> userMap = new HashMap<String, String>();
userMap.put("username", "guest");
assertTrue(o.isAllowed(userMap, "frob", company));
}

@Test
public void testAllowModel() throws Exception {
User auditor = new User("auditor");

assertTrue(o.isAllowed(auditor, "list", Company.class));
assertFalse(o.isAllowed(auditor, "list", Widget.class));
}

@Test
public void testGetAllowedActions() throws Exception {

Oso o = new Oso();
o.registerClass(User.class, "User");
o.registerClass(Widget.class, "Widget");

o.loadStr(
"allow(_actor: User{name: \"sally\"}, action, _resource: Widget{id: 1})"
+ " if action in [\"CREATE\", \"READ\"];");

User actor = new User("sally");
Widget widget = new Widget(1);
HashSet<Object> actions = o.getAllowedActions(actor, widget);

assertEquals(actions.size(), 2);
assertTrue(actions.contains("CREATE"));
assertTrue(actions.contains("READ"));

o.clearRules();

o.loadStr(
"allow(_actor: User{name: \"fred\"}, action, _resource: Widget{id: 2})"
+ " if action in [1, 2, 3, 4];");

User actor2 = new User("fred");
Widget widget2 = new Widget(2);
HashSet<Object> actions2 = o.getAllowedActions(actor2, widget2);

assertEquals(actions2.size(), 4);
assertTrue(actions2.contains(1));
assertTrue(actions2.contains(2));
assertTrue(actions2.contains(3));
assertTrue(actions2.contains(4));

User actor3 = new User("doug");
Widget widget3 = new Widget(4);
assertTrue(o.getAllowedActions(actor3, widget3).isEmpty());
}

@Test
public void testGetAllowedActionsWildcard() throws Exception {
Oso o = new Oso();

o.registerClass(User.class, "User");
o.registerClass(Widget.class, "Widget");

o.loadStr("allow(_actor: User{name: \"John\"}, _action, _resource: Widget{id: 1});");

User actor = new User("John");
Widget widget = new Widget(1);

assertEquals(Set.of("*"), o.getAllowedActions(actor, widget, true));
assertThrows(Exceptions.OsoException.class, () -> o.getAllowedActions(actor, widget, false));
}

@Test
public void testNotEqualOperator() {
Oso oso = new Oso();
oso.registerClass(User.class, "User");
oso.loadStr("allow(actor: User, _action, _resource) if actor != nil;");
assertFalse(oso.isAllowed(null, "foo", "foo"));
}
}

0 comments on commit f8942c6

Please sign in to comment.