package com.robotoworks.mechanoid.net.validation; import java.util.HashSet; import java.util.Set; import org.eclipse.emf.ecore.xml.type.internal.RegEx; import org.eclipse.emf.ecore.xml.type.internal.RegEx.RegularExpression; import org.eclipse.xtext.common.types.JvmType; import org.eclipse.xtext.common.types.util.TypeReferences; import org.eclipse.xtext.validation.Check; import org.eclipse.xtext.xbase.lib.IterableExtensions; import com.google.inject.Inject; import com.robotoworks.mechanoid.MechanoidPlugin; import com.robotoworks.mechanoid.net.netModel.BodyBlock; import com.robotoworks.mechanoid.net.netModel.BooleanLiteral; import com.robotoworks.mechanoid.net.netModel.BooleanType; import com.robotoworks.mechanoid.net.netModel.Client; import com.robotoworks.mechanoid.net.netModel.ComplexTypeLiteral; import com.robotoworks.mechanoid.net.netModel.EnumMember; import com.robotoworks.mechanoid.net.netModel.EnumTypeDeclaration; import com.robotoworks.mechanoid.net.netModel.HeaderBlock; import com.robotoworks.mechanoid.net.netModel.HttpMethod; import com.robotoworks.mechanoid.net.netModel.HttpMethodType; import com.robotoworks.mechanoid.net.netModel.IntrinsicType; import com.robotoworks.mechanoid.net.netModel.Literal; import com.robotoworks.mechanoid.net.netModel.Model; import com.robotoworks.mechanoid.net.netModel.NetModelPackage; import com.robotoworks.mechanoid.net.netModel.NumericLiteral; import com.robotoworks.mechanoid.net.netModel.NumericType; import com.robotoworks.mechanoid.net.netModel.ParamsBlock; import com.robotoworks.mechanoid.net.netModel.ResponseBlock; import com.robotoworks.mechanoid.net.netModel.SimpleMemberAssignment; import com.robotoworks.mechanoid.net.netModel.StringLiteral; import com.robotoworks.mechanoid.net.netModel.StringType; import com.robotoworks.mechanoid.validation.MechanoidIssueCodes; import com.robotoworks.mechanoid.validation.MechanoidLibClasspathValidationHelper; public class NetModelJavaValidator extends AbstractNetModelJavaValidator { @Inject TypeReferences typeReferences; @Inject MechanoidLibClasspathValidationHelper libValidationHelper; @Check public void checkMechanoidLibOnClasspath(Model m) { if(libValidationHelper.shouldValidateMechanoidLibOnClassPath(m)) { JvmType type = typeReferences.findDeclaredType(MechanoidPlugin.MECHANOID_LIB_CLASS, m); if(type == null) { error("mechanoid.jar is required in your /libs folder or on the classpath", NetModelPackage.Literals.MODEL__PACKAGE_NAME, MechanoidIssueCodes.MISSING_MECHANOID_LIBS); } } } @Check public void checkValueAssignment(SimpleMemberAssignment assignment){ IntrinsicType type = assignment.getMember().getType(); Literal defaultValue = assignment.getDefaultValue(); if(defaultValue == null) { return; } if(type instanceof StringType) { if(!(defaultValue instanceof StringLiteral)) { error("Type mismatch", NetModelPackage.Literals.SIMPLE_MEMBER_ASSIGNMENT__DEFAULT_VALUE ); } } else if(type instanceof BooleanType) { if(!(defaultValue instanceof BooleanLiteral)) { error("Type mismatch", NetModelPackage.Literals.SIMPLE_MEMBER_ASSIGNMENT__DEFAULT_VALUE ); } // TODO Check each numeric type (double, integer, long, etc) } else if(type instanceof NumericType) { if(!(defaultValue instanceof NumericLiteral)) { error("Type mismatch", NetModelPackage.Literals.SIMPLE_MEMBER_ASSIGNMENT__DEFAULT_VALUE ); } } } @Check public void checkBodyIsValid(HttpMethod method){ Iterable<BodyBlock> bodyBlocks = IterableExtensions.filter(method.getBlocks(), BodyBlock.class); int numBodyBlocks = IterableExtensions.size(bodyBlocks); HttpMethodType methodType = method.getType(); if(methodType == HttpMethodType.POST || methodType == HttpMethodType.PUT) { if(numBodyBlocks > 1) { BodyBlock lastBlock = IterableExtensions.last(bodyBlocks); error("Body block already defined", method, NetModelPackage.Literals.HTTP_METHOD__BLOCKS, method.getBlocks().indexOf(lastBlock)); } return; } if(numBodyBlocks > 0) { BodyBlock lastBlock = IterableExtensions.last(bodyBlocks); error("body not valid for " + methodType.getLiteral() + " methods", method, NetModelPackage.Literals.HTTP_METHOD__BLOCKS, method.getBlocks().indexOf(lastBlock)); } } @Check public void checkBlockCardinality(HttpMethod method){ checkBlockCardinality(method, ParamsBlock.class, "params", 0, 1); checkBlockCardinality(method, ResponseBlock.class, "response", 0, 1); checkBlockCardinality(method, HeaderBlock.class, "headers", 0, 1); } @Check public void checkBlockCardinality(Client client){ checkBlockCardinality(client, ParamsBlock.class, "params", 0, 1); checkBlockCardinality(client, HeaderBlock.class, "headers", 0, 1); } private <T> void checkBlockCardinality(HttpMethod method, Class<T> blockClazz, String blockType, int min, int max) { Iterable<T> blocks = IterableExtensions.filter(method.getBlocks(), blockClazz); int numBlocks = IterableExtensions.size(blocks); if(numBlocks < min || numBlocks > max) { T lastBlock = IterableExtensions.last(blocks); error(blockType + " already defined", method, NetModelPackage.Literals.HTTP_METHOD__BLOCKS, method.getBlocks().indexOf(lastBlock)); } } private <T> void checkBlockCardinality(Client client, Class<T> blockClazz, String blockType, int min, int max) { Iterable<T> blocks = IterableExtensions.filter(client.getBlocks(), blockClazz); int numBlocks = IterableExtensions.size(blocks); if(numBlocks < min || numBlocks > max) { T lastBlock = IterableExtensions.last(blocks); error(blockType + " already defined", client, NetModelPackage.Literals.CLIENT__BLOCKS, client.getBlocks().indexOf(lastBlock)); } } @Check public void responseSuperValidIfResponseIsLiteral(ResponseBlock response){ if(response.getSuperType() != null && response.getType() != null && !(response.getType() instanceof ComplexTypeLiteral)){ error("Response must be a literal object in order to do this", NetModelPackage.Literals.RESPONSE_BLOCK__SUPER_TYPE); } } @Check public void enumMembersAssignNumericValuesOnlyIfEnumExtendsInteger(EnumMember member){ EnumTypeDeclaration decl = (EnumTypeDeclaration) member.eContainer().eContainer(); if(member.isAssignment() && decl.getSuperType() == null){ error("Members can only be assigned values of the enum extends Integer", NetModelPackage.Literals.ENUM_MEMBER__VALUE); } } @Check public void allEnumMembersAssignUniqueNumericValuesIfEnumExtendsInteger(EnumTypeDeclaration decl){ Set<Integer> set = new HashSet<Integer>(); boolean someAssigned = false; int numAssigned = 0; for(EnumMember member : decl.getLiteral().getMembers()){ if(member.isAssignment()){ someAssigned = true; numAssigned++; } set.add(member.getValue()); } if(someAssigned){ // First one is assigned if(numAssigned == 1 && decl.getLiteral().getMembers().get(0).isAssignment()){ return; } // Only some are assigned, this is an error else if(numAssigned != decl.getLiteral().getMembers().size()){ error("One value, all values or no values should be assigned", NetModelPackage.Literals.ENUM_TYPE_DECLARATION__LITERAL); return; } if(set.size() != decl.getLiteral().getMembers().size()){ error("Duplicate values are not allowed", NetModelPackage.Literals.ENUM_TYPE_DECLARATION__LITERAL); } } } }