/* * Add transition properties to entity info */ public static void addNavPropertiesToEntityInfo( EntityInfo entityInfo, InteractionModel interactionModel) { IMResourceStateMachine rsm = interactionModel.findResourceStateMachine(entityInfo.getClazz()); if (rsm != null) { for (IMTransition transition : rsm.getEntityStateTransitions()) { List<FieldInfo> properties = entityInfo.getAllFieldInfos(); List<String> annotations = new ArrayList<String>(); if (transition instanceof IMCollectionStateTransition) { // Transition to collection state // TODO fix reciprocal links // annotations.add("@OneToMany(cascade = CascadeType.ALL, mappedBy = \"" + // transition.getTargetStateName() + "\")"); // properties.add(new FieldInfo(transition.getTargetStateName(), "Collection<" + // transition.getTargetEntityName() + ">", annotations)); } else if (transition instanceof IMEntityStateTransition) { // Transition to entity state IMEntityStateTransition t = (IMEntityStateTransition) transition; annotations.add( "@JoinColumn(name = \"" + t.getLinkProperty() + "\", referencedColumnName = \"" + t.getTargetResourceStateMachine().getMappedEntityProperty() + "\", insertable = false, updatable = false)"); annotations.add("@ManyToOne(optional = false)"); properties.add( new FieldInfo( t.getTargetState().getName(), t.getTargetResourceStateMachine().getEntityName(), annotations)); } } } }
/** * Generate project artefacts from conceptual interaction and metadata models. * * @param metadata metadata model * @param interactionModel Conceptual interaction model * @param commands Commands * @param srcOutputPath Path to output directory * @param configOutputPath Path to configuration files directory * @param generateMockResponder Indicates whether to generate artifacts for a mock responder * @return true if successful, false otherwise */ public boolean generateArtifacts( Metadata metadata, InteractionModel interactionModel, Commands commands, File srcOutputPath, File configOutputPath, boolean generateMockResponder) { // Create the entity model String modelName = metadata.getModelName(); EntityModel entityModel = createEntityModelFromMetadata(modelName, metadata); // Add error entities for (IMState state : interactionModel.getErrorHandlerStates()) { EMEntity emEntity = new EMEntity(state.getName()); EMProperty empErrorMvGroup = new EMProperty("ErrorsMvGroup"); empErrorMvGroup.addVocabularyTerm(new EMTerm(TermIdField.TERM_NAME, "true")); empErrorMvGroup.addVocabularyTerm(new EMTerm(TermListType.TERM_NAME, "true")); empErrorMvGroup.addVocabularyTerm(new EMTerm(TermComplexType.TERM_NAME, "true")); emEntity.addProperty(empErrorMvGroup); EMProperty empCode = new EMProperty("Code"); empCode.addVocabularyTerm(new EMTerm(TermComplexGroup.TERM_NAME, "ErrorsMvGroup")); emEntity.addProperty(empCode); EMProperty empInfo = new EMProperty("Info"); empInfo.addVocabularyTerm(new EMTerm(TermComplexGroup.TERM_NAME, "ErrorsMvGroup")); emEntity.addProperty(empInfo); EMProperty empText = new EMProperty("Text"); empText.addVocabularyTerm(new EMTerm(TermComplexGroup.TERM_NAME, "ErrorsMvGroup")); emEntity.addProperty(empText); EMProperty empType = new EMProperty("Type"); empType.addVocabularyTerm(new EMTerm(TermComplexGroup.TERM_NAME, "ErrorsMvGroup")); emEntity.addProperty(empType); entityModel.addEntity(emEntity); } // Obtain resource information String namespace = modelName + Metadata.MODEL_SUFFIX; List<EntityInfo> entitiesInfo = new ArrayList<EntityInfo>(); for (EntityMetadata entityMetadata : metadata.getEntitiesMetadata().values()) { EntityInfo entityInfo = createEntityInfoFromEntityMetadata(namespace, entityMetadata); addNavPropertiesToEntityInfo(entityInfo, interactionModel); entitiesInfo.add(entityInfo); } return generateArtifacts( entityModel, interactionModel, commands, entitiesInfo, srcOutputPath, configOutputPath, generateMockResponder); }
private boolean writeArtefacts( String modelName, List<EntityInfo> entitiesInfo, Commands commands, EntityModel entityModel, InteractionModel interactionModel, File srcOutputPath, File configOutputPath, boolean generateMockResponder) { boolean ok = true; String namespace = modelName + Metadata.MODEL_SUFFIX; interactionModel.setDomain(namespace); // Create the source directory new File(srcOutputPath + "/" + namespace.replace(".", "/")).mkdirs(); // generate metadata.xml if (!writeMetadata(configOutputPath, generateMetadata(entityModel))) { ok = false; } // generate spring configuration files if (!writeSpringConfiguration( configOutputPath, SPRING_CONFIG_FILE, generateSpringConfiguration(namespace, modelName, commands))) { ok = false; } // generate the rim DSL RimDslGenerator rimDslGenerator = new RimDslGenerator(ve); Map<String, String> rims = rimDslGenerator.generateRimDslMap(interactionModel, commands, strictOData); for (String key : rims.keySet()) { String rimDslFilename = key + ".rim"; if (!writeRimDsl(configOutputPath, rimDslFilename, rims.get(key))) { System.out.print("Failed to write " + key); ok = false; break; } } if (generateMockResponder) { // Write JPA classes for (EntityInfo entityInfo : entitiesInfo) { if (!generateJPAEntity(entityInfo, srcOutputPath)) { ok = false; } } // generate persistence.xml if (!writeJPAConfiguration(configOutputPath, generateJPAConfiguration(entitiesInfo))) { ok = false; } // generate spring configuration for JPA database if (!writeSpringConfiguration( configOutputPath, SPRING_RESOURCEMANAGER_FILE, generateSpringResourceManagerContext(modelName))) { ok = false; } // generate responder insert if (!writeResponderDML(configOutputPath, generateResponderDML(entitiesInfo))) { ok = false; } // generate responder settings if (!writeResponderSettings(configOutputPath, generateResponderSettings(modelName))) { ok = false; } } return ok; }
@Test public void testGetRIM() { // Parse the test metadata MetadataParser parser = new MetadataParser(); InputStream is = parser.getClass().getClassLoader().getResourceAsStream(METADATA_AIRLINE_XML_FILE); Metadata metadata = parser.parse(is); Assert.assertNotNull(metadata); // Define the interaction model InteractionModel interactionModel = new InteractionModel(metadata); IMResourceStateMachine rsmFlightSchedule = interactionModel.findResourceStateMachine("FlightSchedule"); IMResourceStateMachine rsmAirport = interactionModel.findResourceStateMachine("Airport"); IMResourceStateMachine rsmFlight = interactionModel.findResourceStateMachine("Flight"); IMResourceStateMachine rsmPassenger = interactionModel.findResourceStateMachine("Passenger"); rsmFlight.addTransitionToEntityState( "flight", rsmFlightSchedule, "flightschedule", "flightScheduleNum", null); rsmFlightSchedule.addTransitionToEntityState( "flightschedule", rsmAirport, "departureAirport", "departureAirportCode", null); rsmFlightSchedule.addTransitionToEntityState( "flightschedule", rsmAirport, "arrivalAirport", "arrivalAirportCode", null); rsmAirport.addTransitionToCollectionState( "airport", rsmFlightSchedule, "departures", "departureAirportCode eq '{code}'", "departureAirportCode", null); rsmAirport.addTransitionToCollectionState( "airport", rsmFlightSchedule, "arrivals", "arrivalAirportCode eq '{code}'", "arrivalAirportCode", null); rsmPassenger.addTransitionToEntityState("passenger", rsmFlight, "flight", "flightID", null); // Run the generator JPAResponderGen generator = new JPAResponderGen(true); Commands commands = JPAResponderGen.getDefaultCommands(); String rimDSL = null; try { InputStream isRimDsl = generator.getRIM(interactionModel, commands); assertNotNull(isRimDsl); rimDSL = CharStreams.toString(new InputStreamReader(isRimDsl, "UTF-8")); } catch (Exception age) { fail(age.getMessage()); } // Check the rim dsl assertTrue(rimDSL.contains("initial resource ServiceDocument")); assertTrue(rimDSL.contains("GET -> FlightSchedules")); assertTrue(rimDSL.contains("resource FlightSchedules")); assertTrue( rimDSL.contains( "GET *-> flightschedule {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( rimDSL.contains( "GET *-> flightschedule_departureAirport {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue(rimDSL.contains("resource flightschedule_departureAirport")); assertTrue(rimDSL.contains("path: \"/FlightSchedules({id})/departureAirport\"")); assertTrue(rimDSL.contains("GET -> Passengers")); assertTrue(rimDSL.contains("resource Passengers")); }
/* * To support resource state transitions (as opposed to application state transitions) * we use a pseudo state in our resource interaction model. A pseudo state does not necessarily * have an addressable uri, and always has actions. */ @Test public void testIMWithResourcePseudoStates() { // Parse the test metadata MetadataParser parser = new MetadataParser(); InputStream is = parser.getClass().getClassLoader().getResourceAsStream(METADATA_AIRLINE_XML_FILE); Metadata metadata = parser.parse(is); Assert.assertNotNull(metadata); // Define the interaction model InteractionModel interactionModel = new InteractionModel(metadata); // Add CRUD pseudo states to an entity/entityset IMResourceStateMachine rsmAirport = interactionModel.findResourceStateMachine("Airport"); rsmAirport.addPseudoStateTransition( "Airports", "created", "Airports", "POST", null, "CreateEntity", null, true); rsmAirport.addPseudoStateTransition( "airport", "updated", "airport", "PUT", null, "UpdateEntity", "edit", false); rsmAirport.addPseudoStateTransition( "airport", "deleted", "DELETE", null, "DeleteEntity", "edit", false); // Run the generator MockGenerator generator = new MockGenerator(); boolean status = generator.generateArtifacts( metadata, interactionModel, new File("target/FlightResponder/classes"), new File("target/FlightResponder/classes"), true); // Check results assertTrue(status); // Test rim dsl assertTrue(generator.generatedRimDsl.contains("POST -> Airports_created")); assertTrue(generator.generatedRimDsl.contains("PUT *-> airport_updated")); assertTrue(generator.generatedRimDsl.contains("PUT -> airport_updated")); assertTrue(generator.generatedRimDsl.contains("DELETE *-> airport_deleted")); assertTrue(generator.generatedRimDsl.contains("DELETE -> airport_deleted")); assertTrue(generator.generatedRimDsl.contains("resource Airports_created")); assertTrue( generator.generatedRimDsl.contains( "resource Airports_created {" + RIM_LINE_SEP + "\ttype: item" + RIM_LINE_SEP + "\tentity: Airport" + RIM_LINE_SEP + "\tactions [ CreateEntity ]" + RIM_LINE_SEP + "\tpath: \"/Airports()\"")); assertTrue( generator.generatedRimDsl.contains( "resource airport_updated {" + RIM_LINE_SEP + "\ttype: item" + RIM_LINE_SEP + "\tentity: Airport" + RIM_LINE_SEP + "\tactions [ UpdateEntity ]" + RIM_LINE_SEP + "\trelations [ \"edit\" ]" + RIM_LINE_SEP + "\tpath: \"/Airports('{id}')\"")); assertTrue( generator.generatedRimDsl.contains( "resource airport_deleted {" + RIM_LINE_SEP + "\ttype: item" + RIM_LINE_SEP + "\tentity: Airport" + RIM_LINE_SEP + "\tactions [ DeleteEntity ]" + RIM_LINE_SEP + "\trelations [ \"edit\" ]" + RIM_LINE_SEP + "\tpath: \"/Airports('{id}')/deleted\"")); assertTrue( generator.generatedRimDsl.contains( "resource airport {" + RIM_LINE_SEP + "\ttype: item" + RIM_LINE_SEP + "\tentity: Airport" + RIM_LINE_SEP + "\tview: GETEntity" + RIM_LINE_SEP + "\tpath: \"/Airports('{id}')\"" + RIM_LINE_SEP + "\tPUT -> airport_updated {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{code}\" ]" + RIM_LINE_SEP + "\t}" + RIM_LINE_SEP + "\tDELETE -> airport_deleted {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{code}\" ]" + RIM_LINE_SEP + "\t}")); }
@Test public void testRIMWithoutReciprocalLinks() { // Parse the test metadata MetadataParser parser = new MetadataParser(); InputStream is = parser.getClass().getClassLoader().getResourceAsStream(METADATA_AIRLINE_XML_FILE); Metadata metadata = parser.parse(is); Assert.assertNotNull(metadata); // Define the interaction model InteractionModel interactionModel = new InteractionModel(metadata); // Do not specify a reciprocal link IMResourceStateMachine rsmFlightSchedule = interactionModel.findResourceStateMachine("FlightSchedule"); IMResourceStateMachine rsmAirport = interactionModel.findResourceStateMachine("Airport"); IMResourceStateMachine rsmFlight = interactionModel.findResourceStateMachine("Flight"); IMResourceStateMachine rsmPassenger = interactionModel.findResourceStateMachine("Passenger"); rsmFlight.addTransitionToEntityState( "flight", rsmFlightSchedule, "flightschedule", "flightScheduleNum", null); rsmFlightSchedule.addTransitionToEntityState( "flightschedule", rsmAirport, "departureAirport", "departureAirportCode", null); rsmFlightSchedule.addTransitionToEntityState( "flightschedule", rsmAirport, "arrivalAirport", "arrivalAirportCode", null); rsmAirport.addTransitionToCollectionState( "airport", rsmFlightSchedule, "departures", "departureAirportCode eq '{code}'", "departureAirportCode", "departures"); rsmAirport.addTransitionToCollectionState( "airport", rsmFlightSchedule, "arrivals", "arrivalAirportCode eq '{code}'", "arrivalAirportCode", "arrivals"); rsmPassenger.addTransitionToEntityState("passenger", rsmFlight, "flight", "flightID", "flight"); // Run the generator MockGenerator generator = new MockGenerator(); boolean status = generator.generateArtifacts( metadata, interactionModel, new File("target/FlightResponder/classes"), new File("target/FlightResponder/classes"), true); // Check results assertTrue(status); // Test rim dsl assertTrue( generator.generatedRimDsl.contains( "GET *-> flightschedule_departureAirport {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET -> flightschedule_departureAirport {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET *-> flightschedule_arrivalAirport {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET -> flightschedule_arrivalAirport {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET -> airport_arrivals {" + RIM_LINE_SEP + "\t\ttitle: \"arrivals\"" + RIM_LINE_SEP + "\t\tparameters [ id=\"{code}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET -> airport_departures {" + RIM_LINE_SEP + "\t\ttitle: \"departures\"" + RIM_LINE_SEP + "\t\tparameters [ id=\"{code}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET -> passenger_flight {" + RIM_LINE_SEP + "\t\ttitle: \"flight\"" + RIM_LINE_SEP + "\t\tparameters [ id=\"{passengerNo}\" ]" + RIM_LINE_SEP + "\t}")); }
@Test public void testGeneratedArtifactsFromConceptualModels() { // Parse the test metadata MetadataParser parser = new MetadataParser(); InputStream is = parser.getClass().getClassLoader().getResourceAsStream(METADATA_AIRLINE_XML_FILE); Metadata metadata = parser.parse(is); Assert.assertNotNull(metadata); // Define the interaction model InteractionModel interactionModel = new InteractionModel(metadata); IMResourceStateMachine rsmFlightSchedule = interactionModel.findResourceStateMachine("FlightSchedule"); IMResourceStateMachine rsmAirport = interactionModel.findResourceStateMachine("Airport"); IMResourceStateMachine rsmFlight = interactionModel.findResourceStateMachine("Flight"); IMResourceStateMachine rsmPassenger = interactionModel.findResourceStateMachine("Passenger"); rsmFlight.addTransitionToEntityState( "flight", rsmFlightSchedule, "flightschedule", "flightScheduleNum", null); rsmFlightSchedule.addTransitionToEntityState( "flightschedule", rsmAirport, "departureAirport", "departureAirportCode", null); rsmFlightSchedule.addTransitionToEntityState( "flightschedule", rsmAirport, "arrivalAirport", "arrivalAirportCode", null); rsmAirport.addTransitionToCollectionState( "airport", rsmFlightSchedule, "departures", "departureAirportCode eq '{code}'", "departureAirportCode", null); rsmAirport.addTransitionToCollectionState( "airport", rsmFlightSchedule, "arrivals", "arrivalAirportCode eq '{code}'", "arrivalAirportCode", null); rsmPassenger.addTransitionToEntityState("passenger", rsmFlight, "flight", "flightID", null); // Run the generator MockGenerator generator = new MockGenerator(); boolean status = generator.generateArtifacts( metadata, interactionModel, new File("target/FlightResponder/classes"), new File("target/FlightResponder/classes"), true); // Check results assertTrue(status); assertTrue(generator.generatedClasses.size() == 4); assertTrue(generator.generatedClasses.get(0).contains("public class Flight")); assertTrue(generator.generatedClasses.get(1).contains("public class Airport")); assertTrue(generator.generatedClasses.get(2).contains("public class FlightSchedule")); assertTrue(generator.generatedClasses.get(3).contains("public class Passenger")); assertTrue(generator.generateResponderDML.contains("INSERT INTO `Flight`(")); assertTrue(generator.generateResponderDML.contains("INSERT INTO `Airport`(")); assertTrue(generator.generateResponderDML.contains("INSERT INTO `FlightSchedule`(")); assertTrue(generator.generateResponderDML.contains("INSERT INTO `Passenger`(")); assertTrue( generator.generatedPersistenceXML.contains("<class>FlightResponderModel.Flight</class>")); assertTrue( generator.generatedPersistenceXML.contains("<class>FlightResponderModel.Airport</class>")); assertTrue( generator.generatedPersistenceXML.contains( "<class>FlightResponderModel.FlightSchedule</class>")); assertTrue( generator.generatedPersistenceXML.contains( "<class>FlightResponderModel.Passenger</class>")); assertTrue( generator.generatedSpringXML.contains( "<bean id=\"behaviour\" class=\"FlightResponderModel.FlightResponderBehaviour\" />")); assertTrue( generator.generatedSpringResourceManagerXML.contains( "<constructor-arg name=\"namespace\" value=\"FlightResponder\" />")); // Test rim dsl assertTrue(generator.generatedRimDsl.contains("initial resource ServiceDocument")); assertTrue(generator.generatedRimDsl.contains("GET -> FlightSchedules")); assertTrue(generator.generatedRimDsl.contains("resource FlightSchedules")); assertTrue( generator.generatedRimDsl.contains( "GET *-> flightschedule {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue( generator.generatedRimDsl.contains( "GET *-> flightschedule_departureAirport {" + RIM_LINE_SEP + "\t\tparameters [ id=\"{flightScheduleID}\" ]" + RIM_LINE_SEP + "\t}")); assertTrue(generator.generatedRimDsl.contains("resource flightschedule_departureAirport")); assertTrue( generator.generatedRimDsl.contains("path: \"/FlightSchedules({id})/departureAirport\"")); assertTrue(generator.generatedRimDsl.contains("GET -> Passengers")); assertTrue(generator.generatedRimDsl.contains("resource Passengers")); }