Skip to content

Commit

Permalink
Fix for multiple CoordinatorRole/MemberRole (even though it will never
Browse files Browse the repository at this point in the history
be used since multiple instances of these annotations are not allowed).
  • Loading branch information
jiracekz committed Mar 4, 2015
1 parent f1907d6 commit 186a19c
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import cz.cuni.mff.d3s.deeco.annotations.Component;
import cz.cuni.mff.d3s.deeco.annotations.CoordinatorRole;
Expand Down Expand Up @@ -174,8 +176,13 @@ void checkRolesImplementation(List<Parameter> parameters, Class<?>[] coordinator
}

/**
* Checks that a given knowledge path is valid in given roles. Works only for ensembles membership
* Checks that a given knowledge path is valid. Works only for ensembles membership
* condition and knowledge exchange functions.
*
* A valid knowledge path must have at least two nodes (first being coord/member and second being
* a field name). More nodes can be present. A knowledge path must also exist in at least one
* role specified for the member/coordinator. The last condition does not apply if the role list
* for the member/coordinator is empty.
* @param type Type of the expression
* @param knowledgePath The knowledge path
* @param coordinatorRoleAnnotations An array of coordinator role classes
Expand Down Expand Up @@ -221,14 +228,25 @@ private void checkKnowledgePath(Type type, KnowledgePath knowledgePath, Class<?>
throw new AnnotationCheckerException("A knowledge path's second element should be a field name.");
}

// test the knowledge path against all roles
// Test the knowledge path against all roles
// It is sufficient that the field belongs to at least one of the roles
boolean satisfiesAnyRole = false;
for (Class<?> roleClass : roleClasses) {
if (!isFieldInRole(type, fieldNameSequence, roleClass)) {
throw new AnnotationCheckerException("The knowledge path '" + knowledgePath.toString() + "'"
+ (type != null ? " of type " + type : "") + " is not valid for the role '" + roleClass.getSimpleName() + "'. "
+ "Check whether the field (or sequence of fields) exists in the role and that it has correct type(s) and is public, nonstatic and non@Local");
if (isFieldInRole(type, fieldNameSequence, roleClass)) {
satisfiesAnyRole = true;
break; // one role is enough
}
}

String roleClassNames = String.join(", ",
Arrays.asList(roleClasses).stream().map(r -> r.getSimpleName()).collect(Collectors.toList()));

if (!satisfiesAnyRole && roleClasses.length > 0) {
throw new AnnotationCheckerException("The knowledge path '" + knowledgePath.toString() + "'"
+ (type != null ? " of type " + type : "") + " is not valid for any of the roles: " + roleClassNames + ". "
+ "Check whether the field (or sequence of fields) exists in the role and that it has correct type(s) and is public, nonstatic and non@Local");

}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -753,18 +753,23 @@ class RoleClass3 {

RolesAnnotationChecker checker = spy(new RolesAnnotationChecker());
Mockito.doReturn(true).when(checker).isFieldInRole(any(), any(), any());
Mockito.doReturn(false).when(checker).isFieldInRole(any(), any(), Mockito.eq(RoleClass2.class));

// It is sufficient if the field is present in at least one role. When the isFieldInRole
// method returns always true, only the first role is tested.
// When the isFieldRole returns false, then also the second role has to be tested (and this
// must return true, else we would get an exception)
checker.checkRolesImplementation(getTestParameters(), coordinatorRoles, memberRoles);
verify(checker, times(1)).isFieldInRole(Integer.class, Arrays.asList("x"), RoleClass1.class);
verify(checker, times(1)).isFieldInRole(Integer.class, Arrays.asList("x"), RoleClass2.class);
//verify(checker, times(1)).isFieldInRole(Integer.class, Arrays.asList("x"), RoleClass2.class);
verify(checker, times(1)).isFieldInRole(Long.class, Arrays.asList("a", "b"), RoleClass1.class);
verify(checker, times(1)).isFieldInRole(Long.class, Arrays.asList("a", "b"), RoleClass2.class);
//verify(checker, times(1)).isFieldInRole(Long.class, Arrays.asList("a", "b"), RoleClass2.class);
verify(checker, times(1)).isFieldInRole(null, Arrays.asList("id"), RoleClass1.class);
verify(checker, times(1)).isFieldInRole(null, Arrays.asList("id"), RoleClass2.class); // TODO this needs subtyping approval
//verify(checker, times(1)).isFieldInRole(null, Arrays.asList("id"), RoleClass2.class); // TODO this needs subtyping approval
verify(checker, times(1)).isFieldInRole(null, Arrays.asList("y"), RoleClass2.class);
verify(checker, times(1)).isFieldInRole(null, Arrays.asList("y"), RoleClass3.class);
verify(checker, times(1)).isFieldInRole(String.class, Arrays.asList("z"), RoleClass1.class);
verify(checker, times(1)).isFieldInRole(String.class, Arrays.asList("z"), RoleClass2.class);
//verify(checker, times(1)).isFieldInRole(String.class, Arrays.asList("z"), RoleClass2.class);
verify(checker, times(1)).isFieldInRole(_Struct_String.class.getGenericSuperclass(), Arrays.asList("s"), RoleClass2.class);
verify(checker, times(1)).isFieldInRole(_Struct_String.class.getGenericSuperclass(), Arrays.asList("s"), RoleClass3.class);

Expand All @@ -781,32 +786,42 @@ class RoleClass1 {
public Integer y;
}

class RoleAnnotationImpl implements CoordinatorRole, MemberRole {
@Override
public Class<?> value() {
return RoleClass1.class;
}

@Override
public Class<? extends Annotation> annotationType() {
return RoleAnnotationImpl.class;
}
@Role
class RoleClass2 {
public Integer x;
public String z;

}

Class<?>[] roles = new Class<?>[] {RoleClass1.class};
Class<?>[] roles = new Class<?>[] {RoleClass1.class, RoleClass2.class};

Parameter param1 = RuntimeMetadataFactory.eINSTANCE.createParameter();
param1.setKind(ParameterKind.IN);
param1.setKnowledgePath(KnowledgePathHelper.createKnowledgePath("coord.x", PathOrigin.ENSEMBLE));
param1.setType(Integer.class);
param1.setGenericType(Integer.class);

RolesAnnotationChecker checker = spy(new RolesAnnotationChecker());
Mockito.doReturn(false).when(checker).isFieldInRole(any(), any(), any());

exception.expect(AnnotationCheckerException.class);
exception.expectMessage("The knowledge path '<COORDINATOR>.x' is not valid for the role 'RoleClass1'. Check whether the field (or sequence of fields) exists in the role and that it has correct type(s) and is public, nonstatic and non@Local");
exception.expectMessage("The knowledge path '<COORDINATOR>.x' of type " + Integer.class + " is not valid for any of the roles: RoleClass1, RoleClass2. Check whether the field (or sequence of fields) exists in the role and that it has correct type(s) and is public, nonstatic and non@Local");

AnnotationCheckerException ex = null;
try {
checker.checkRolesImplementation(Arrays.asList(param1), roles, roles);
} catch (AnnotationCheckerException e) {
ex = e;
}

// verify that both roles were tested
verify(checker, times(1)).isFieldInRole(Integer.class, Arrays.asList("x"), RoleClass1.class);
verify(checker, times(1)).isFieldInRole(Integer.class, Arrays.asList("x"), RoleClass2.class);
verify(checker, times(1)).checkRolesImplementation(any(), any(), any());
verifyNoMoreInteractions(checker);

checker.checkRolesImplementation(Arrays.asList(param1), roles, roles);
if (ex != null)
throw ex;
}


Expand Down

0 comments on commit 186a19c

Please sign in to comment.