azkaban-developers

Details

diff --git a/src/java/azkaban/scheduler/ScheduledFlow.java b/src/java/azkaban/scheduler/ScheduledFlow.java
index 20a22b8..54a7211 100644
--- a/src/java/azkaban/scheduler/ScheduledFlow.java
+++ b/src/java/azkaban/scheduler/ScheduledFlow.java
@@ -103,7 +103,7 @@ public class ScheduledFlow {
 			DateTime firstSchedTime,
 			ReadablePeriod period)
 	{
-		this(scheduleId, projectId, flowId, user, userSubmit, submitTime, firstSchedTime, new DateTime(), period);
+		this(scheduleId, projectId, flowId, user, userSubmit, submitTime, firstSchedTime, new DateTime().withZone(firstSchedTime.getZone()), period);
 	}
 
 	public ScheduledFlow(
@@ -115,7 +115,7 @@ public class ScheduledFlow {
 			DateTime submitTime, 
 			DateTime firstSchedTime) 
 	{
-		this(scheduleId, projectId, flowId, user, userSubmit, submitTime, firstSchedTime, new DateTime(), null);
+		this(scheduleId, projectId, flowId, user, userSubmit, submitTime, firstSchedTime, new DateTime().withZone(firstSchedTime.getZone()), null);
 	}
 
 	/**
diff --git a/src/java/azkaban/utils/DirectoryFlowLoader.java b/src/java/azkaban/utils/DirectoryFlowLoader.java
index d376522..ff1cca2 100644
--- a/src/java/azkaban/utils/DirectoryFlowLoader.java
+++ b/src/java/azkaban/utils/DirectoryFlowLoader.java
@@ -4,6 +4,7 @@ import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -56,7 +57,7 @@ public class DirectoryFlowLoader {
 		nodeDependencies = new HashMap<String, Map<String, Edge>>();
 
 		// Load all the props files and create the Node objects
-		loadProjectFromDir(baseDirectory.getPath(), baseDirectory);
+		loadProjectFromDir(baseDirectory.getPath(), baseDirectory, null);
 		
 		// Create edges and find missing dependencies
 		resolveDependencies();
@@ -66,9 +67,9 @@ public class DirectoryFlowLoader {
 
 	}
 	
-	private void loadProjectFromDir(String base, File dir) {
+	private void loadProjectFromDir(String base, File dir, Props parent) {
 		File[] propertyFiles = dir.listFiles(new SuffixFilter(PROPERTY_SUFFIX));
-		Props parent = null;
+		Arrays.sort(propertyFiles);
 		
 		for (File file: propertyFiles) {
 			String relative = getRelativeFilePath(base, file.getPath());
@@ -85,7 +86,8 @@ public class DirectoryFlowLoader {
 			logger.info("Adding " + relative);
 			propsList.add(parent);
 		}
-
+		
+		
 		// Load all Job files. If there's a duplicate name, then we don't load
 		File[] jobFiles = dir.listFiles(new SuffixFilter(JOB_SUFFIX));
 		for (File file: jobFiles) {
@@ -128,7 +130,7 @@ public class DirectoryFlowLoader {
 		
 		File[] subDirs = dir.listFiles(DIR_FILTER);
 		for (File file: subDirs) {
-			loadProjectFromDir(base, file);
+			loadProjectFromDir(base, file, parent);
 		}
 	}
 	
diff --git a/src/java/azkaban/utils/Mailman.java b/src/java/azkaban/utils/Mailman.java
index 7fc828a..094ad55 100644
--- a/src/java/azkaban/utils/Mailman.java
+++ b/src/java/azkaban/utils/Mailman.java
@@ -17,9 +17,14 @@
 package azkaban.utils;
 
 import java.util.List;
+import java.util.Properties;
 
+import javax.mail.Message;
 import javax.mail.MessagingException;
+import javax.mail.Session;
 import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
 
 
 import org.apache.commons.mail.EmailException;
@@ -27,6 +32,8 @@ import org.apache.commons.mail.SimpleEmail;
 
 import org.apache.log4j.Logger;
 
+import com.sun.mail.smtp.SMTPTransport;
+
 /**
  * The mailman send you mail, if you ask him
  * 
@@ -39,6 +46,8 @@ public class Mailman {
 	private final String _mailUser;
 	private final String _mailPassword;
 	private final String _mailSender;
+	
+	private final String protocol = "smtp";
 
 	public Mailman(String mailHost, String mailUser, String mailPassword,
 			String mailSender) {
@@ -50,6 +59,44 @@ public class Mailman {
 
 	public void sendEmail(String fromAddress, List<String> toAddress,
 			String subject, String body) throws MessagingException {
+<<<<<<< HEAD
+=======
+
+		//session
+		Properties props = new Properties();
+		props.put("mail." + protocol + ".host", _mailHost);
+		props.put("mail." + protocol + ".auth", "true");
+		
+		Session session = Session.getInstance(props, null);
+		session.setDebug(true);
+		
+		//email message
+		Message msg = new MimeMessage(session);
+		msg.setFrom(new InternetAddress(fromAddress));
+		for(String str : toAddress) {
+			msg.addRecipients(Message.RecipientType.TO, InternetAddress.parse(str));
+		}
+		
+		msg.setSubject(subject);
+		msg.setText(body);
+		
+		//transport
+		SMTPTransport t = (SMTPTransport)session.getTransport(protocol);
+		
+		try {
+			t.connect(_mailHost, _mailUser, _mailPassword);
+			t.sendMessage(msg, msg.getAllRecipients());
+		}
+		catch (Exception e) {
+			logger.error(e);
+		}
+		finally {
+			t.close();
+		}
+		
+		
+		
+>>>>>>> 7f1fd5f465d15e01aae522eceac6fc7863031bcb
 //		SimpleEmail email = new SimpleEmail();
 //
 //		try {
diff --git a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index 720f8f5..3f9caf5 100644
--- a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -641,8 +641,20 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
 						}
 						
 						// Resolve property dependencies
-						String source = node.getPropsSource();
-						page.add("properties", source);
+						ArrayList<String> source = new ArrayList<String>(); 
+						String nodeSource = node.getPropsSource();
+						if(nodeSource != null) {
+							source.add(nodeSource);
+							Props parent = flow.getFlowProps(nodeSource).getProps();
+							while(parent.getParent() != null) {
+								source.add(parent.getParent().getSource());
+								parent = parent.getParent(); 
+							}
+						}
+						if(!source.isEmpty()) {
+							page.add("properties", source);
+						}
+						
 
 						ArrayList<Pair<String,String>> parameters = new ArrayList<Pair<String, String>>();
 						// Parameter
diff --git a/src/java/azkaban/webapp/servlet/ScheduleServlet.java b/src/java/azkaban/webapp/servlet/ScheduleServlet.java
index bafb86b..211ea49 100644
--- a/src/java/azkaban/webapp/servlet/ScheduleServlet.java
+++ b/src/java/azkaban/webapp/servlet/ScheduleServlet.java
@@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
 import org.joda.time.Months;
 import org.joda.time.Weeks;
 import org.joda.time.Days;
@@ -144,6 +145,8 @@ public class ScheduleServlet extends LoginAbstractAzkabanServlet {
 		int hour = getIntParam(req, "hour");
 		int minutes = getIntParam(req, "minutes");
 		boolean isPm = getParam(req, "am_pm").equalsIgnoreCase("pm");
+		
+		DateTimeZone timezone = getParam(req,  "timezone").equals("UTC") ? DateTimeZone.UTC : DateTimeZone.forID("America/Los_Angeles");
 
 
 		String scheduledDate = req.getParameter("date");
@@ -152,7 +155,7 @@ public class ScheduleServlet extends LoginAbstractAzkabanServlet {
 			day = new LocalDateTime().toDateTime();
 		} else {
 		    try {
-		    	day = DateTimeFormat.forPattern("MM/dd/yyyy").parseDateTime(scheduledDate);
+		    	day = DateTimeFormat.forPattern("MM/dd/yyyy").withZone(timezone).parseDateTime(scheduledDate);
 		    } catch(IllegalArgumentException e) {
 		      	ret.put("error", "Invalid date: '" + scheduledDate + "'");
 		      	return;
@@ -175,7 +178,7 @@ public class ScheduleServlet extends LoginAbstractAzkabanServlet {
 		String userSubmit = user.getUserId();
 		String userExec = userSubmit;//getParam(req, "userExec");
 		String scheduleId = projectId + "." + flowId;
-		DateTime submitTime = new DateTime();
+		DateTime submitTime = new DateTime().withZone(timezone);
 		DateTime firstSchedTime = day.withHourOfDay(hour).withMinuteOfHour(minutes).withSecondOfMinute(0);
 		
 		ScheduledFlow schedFlow = scheduleManager.schedule(scheduleId, projectId, flowId, userExec, userSubmit, submitTime, firstSchedTime, thePeriod);
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index 21a4e8b..96aaedf 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -144,7 +144,10 @@
                                                       <option>pm</option>
                                                       <option>am</option>
                                                     </select>
-                                                    $timezone
+                                                    <select id="timezone">
+                                                      <option>PDT</option>
+                                                      <option>UTC</option>
+                                                    </select>
                                                     on
                                                     <br>
                                                     <p>Date: <input type="text" id="datepicker"></p>
diff --git a/src/java/azkaban/webapp/servlet/velocity/jobpage.vm b/src/java/azkaban/webapp/servlet/velocity/jobpage.vm
index 8dd6bbb..b1f6724 100644
--- a/src/java/azkaban/webapp/servlet/velocity/jobpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/jobpage.vm
@@ -67,7 +67,9 @@
 					</td></tr>
 					<tr><td class="first">Properties:</td><td>
 #if ($properties) 
-						<a>$properties</a>
+#foreach($property in $properties)
+						<a>$property</a><span>,</span>
+#end
 #else
 						<span>No Inherited Properties</span>
 #end
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index 17b9d27..c8aef95 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -871,6 +871,7 @@ azkaban.ScheduleFlowView = Backbone.View.extend({
      var hourVal = $('#hour').val();
      var minutesVal = $('#minutes').val();
      var ampmVal = $('#am_pm').val();
+     var timezoneVal = $('#timezone').val();
      var dateVal = $('#datepicker').val();
      var is_recurringVal = $('#is_recurring').val();
      var periodVal = $('#period').val();
@@ -890,6 +891,7 @@ azkaban.ScheduleFlowView = Backbone.View.extend({
 		hour:hourVal,
 		minutes:minutesVal,
 		am_pm:ampmVal,
+		timezone:timezoneVal,
 		date:dateVal,
 		userExec:"dummy",
 		is_recurring:is_recurringVal,
diff --git a/unit/java/azkaban/test/utils/MailmanTest.java b/unit/java/azkaban/test/utils/MailmanTest.java
new file mode 100644
index 0000000..3406114
--- /dev/null
+++ b/unit/java/azkaban/test/utils/MailmanTest.java
@@ -0,0 +1,58 @@
+package azkaban.test.utils;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import azkaban.utils.Mailman;
+
+
+public class MailmanTest {
+
+	private Mailman mailer;
+	
+	private String user = "cyu";
+	private String password;
+	private String host = "email.corp.linkedin.com";
+	private String mailSender = "cyu@linkedin.com";
+	
+	private Logger logger = Logger.getLogger(Mailman.class);
+	  
+	  @Before
+	public void setUp() {		
+	
+		  mailer = new Mailman(host, user, password, mailSender);
+		  
+
+	  }
+	  
+	  @Test
+	  public void testSendEmail() {
+
+		  String fromAddress = "cyu@linkedin.com";
+		  List<String> toAddress = new ArrayList<String>();
+		  //toAddress.add("cyu@linkedin.com");
+		  toAddress.add("azkaban-test@linkedin.com");
+		  
+		  String subject = "Azkaban Test email subject";
+		  String body = "Azkaban Test email body";
+		  
+		  try {
+			   mailer.sendEmail(fromAddress, toAddress, subject, body);
+		  }
+		  catch (Exception e) {
+			  Assert.assertTrue(true);
+			  //please check email to see if this works
+			  e.printStackTrace();
+		  }
+	    
+	  }
+
+
+}