ProjectManager { public void setJobOverrideProperty(final Project project, final Flow flow, final Props prop, final String jobName, final String source, final User modifier) throws ProjectManagerException { File tempDir = null; Props oldProps = null; String errorMessage = null; final Map<String, Object> eventData = new HashMap<>(); addEventDataFromProject(project, eventData); if (FlowLoaderUtils.isAzkabanFlowVersion20(flow.getAzkabanFlowVersion())) { try { tempDir = Files.createTempDir(); final int flowVersion = this.projectLoader.getLatestFlowVersion(flow.getProjectId(), flow .getVersion(), source); final File flowFile = this.projectLoader.getUploadedFlowFile(flow.getProjectId(), flow .getVersion(), source, flowVersion, tempDir); final String path = flow.getId() + Constants.PATH_DELIMITER + jobName; oldProps = FlowLoaderUtils.getPropsFromYamlFile(path, flowFile); FlowLoaderUtils.setPropsInYamlFile(path, flowFile, prop); this.projectLoader .uploadFlowFile(flow.getProjectId(), flow.getVersion(), flowFile, flowVersion + 1); } catch (final Exception e) { this.logger.error("Failed to set job override property. " + e); errorMessage = e.toString(); } finally { FlowLoaderUtils.cleanUpDir(tempDir); } } else { prop.setSource(jobName + Constants.JOB_OVERRIDE_SUFFIX); oldProps = this.projectLoader.fetchProjectProperty(project, prop.getSource()); if (oldProps == null) { this.projectLoader.uploadProjectProperty(project, prop); } else { this.projectLoader.updateProjectProperty(project, prop); } } eventData.put("modifiedBy", modifier.getUserId()); eventData.put("flowName", flow.getId()); eventData.put("jobOverridden", jobName); final String diffMessage = PropsUtils.getPropertyDiff(oldProps, prop); eventData.put("diffMessage", diffMessage); setProjectEventStatus(errorMessage, eventData); project.fireEventListeners(ProjectEvent.create(project, azkaban.spi.EventType.JOB_PROPERTY_OVERRIDDEN, eventData)); this.projectLoader.postEvent(project, EventType.PROPERTY_OVERRIDE, modifier.getUserId(), diffMessage); return; } @Inject  ProjectManager(final AzkabanProjectLoader azkabanProjectLoader,
      final ProjectLoader loader,
      final ProjectStorageManager projectStorageManager,
      final Props props, final ProjectCache cache); boolean hasFlowTrigger(final Project project, final Flow flow); Props getProps(); List<Project> getUserProjects(final User user); List<Project> getGroupProjects(final User user); List<Project> getUserProjectsByRegex(final User user, final String regexPattern); List<Project> getProjects(); List<Project> getProjectsByRegex(final String regexPattern); Boolean isActiveProject(final int id); Project getProject(final String name); Project getProject(final int id); Project createProject(final String projectName, final String description,
      final User creator); synchronized Project purgeProject(final Project project, final User deleter); synchronized Project removeProject(final Project project, final User deleter); void updateProjectDescription(final Project project, final String description,
      final User modifier); List<ProjectLogEvent> getProjectEventLogs(final Project project,
      final int results, final int skip); Props getPropertiesFromFlowFile(final Flow flow, final String jobName, final String
      flowFileName, final int flowVersion); Props getProperties(final Project project, final Flow flow, final String jobName,
      final String source); Props getJobOverrideProperty(final Project project, final Flow flow, final String jobName,
      final String source); void setJobOverrideProperty(final Project project, final Flow flow, final Props prop,
      final String jobName, final String source, final User modifier); void updateProjectSetting(final Project project); void addProjectProxyUser(final Project project, final String proxyName,
      final User modifier); void removeProjectProxyUser(final Project project, final String proxyName,
      final User modifier); void updateProjectPermission(final Project project, final String name,
      final Permission perm, final boolean group, final User modifier); void removeProjectPermission(final Project project, final String name,
      final boolean group, final User modifier); ProjectFileHandler getProjectFileHandler(final Project project, final int version); Map<String, ValidationReport> uploadProject(final Project project,
      final File archive, final String fileType, final User uploader, final Props additionalProps,
      final String uploaderIPAddr); void updateFlow(final Project project, final Flow flow); void postProjectEvent(final Project project, final EventType type, final String user,
      final String message); boolean loadProjectWhiteList(); void setProjectEventStatus(final String errorMessage, final Map<String, Object> eventData); void postScheduleEvent(final Project project, final azkaban.spi.EventType type, final User user, final Schedule schedule, final String errorMessage);  }
@Test public void testJobOverrideProperty() throws Exception { final User user = new User("testUser5"); final Flow flow = new Flow(flowName); final Node node = new Node(jobName); flow.addNode(node); final Map<String, Flow> flowMap = new HashMap(); flowMap.put(flowName, flow); project.setFlows(flowMap); final Map<String, String> jobParamGroup = new HashMap(); jobParamGroup.put("type", "command"); jobParamGroup.put("command", "sleep 2"); jobParamGroup.put("dependencies", "job0"); final Props overrideParams = new Props(null, jobParamGroup); project.addListener((event) -> { ProjectEvent projectEvent = (ProjectEvent) event; Assert.assertEquals("Event metadata not created as expected.", flowName, projectEvent.getEventData().get("flowName")); Assert.assertEquals("Event metadata not created as expected.", jobName, projectEvent.getEventData().get("jobOverridden")); Assert.assertEquals("Event metadata not created as expected.", diffMsg, projectEvent.getEventData().get("diffMessage")); Assert.assertEquals("Event metadata not created as expected.", "SUCCESS", projectEvent.getEventData().get("projectEventStatus")); }); manager.setJobOverrideProperty(project, flow, overrideParams, jobName, node.getJobSource(), user); }