azkaban-uncached

Details

diff --git a/src/java/azkaban/project/ProjectManager.java b/src/java/azkaban/project/ProjectManager.java
index df73c69..f1ce489 100644
--- a/src/java/azkaban/project/ProjectManager.java
+++ b/src/java/azkaban/project/ProjectManager.java
@@ -229,7 +229,10 @@ public class ProjectManager {
 		// Unzip.
 		File file = null;
 		try {
-			if (fileType.equals("zip")) {
+			if (fileType == null) {
+				throw new ProjectManagerException("Unknown file type for " + archive.getName());
+			}
+			else if ("zip".equals(fileType)) {
 				file = unzipFile(archive);
 			}
 			else {
diff --git a/src/java/azkaban/utils/PropsUtils.java b/src/java/azkaban/utils/PropsUtils.java
index 980bf97..3c720c4 100644
--- a/src/java/azkaban/utils/PropsUtils.java
+++ b/src/java/azkaban/utils/PropsUtils.java
@@ -18,6 +18,7 @@ package azkaban.utils;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -56,11 +57,11 @@ public class PropsUtils {
 	 *            File suffixes to load
 	 * @return The loaded set of schedules
 	 */
-	public static Props loadPropsInDir(Props parent, File dir,
-			String... suffixes) {
+	public static Props loadPropsInDir(Props parent, File dir, String... suffixes) {
 		try {
 			Props props = new Props(parent);
 			File[] files = dir.listFiles();
+			Arrays.sort(files);
 			if (files != null) {
 				for (File f : files) {
 					if (f.isFile() && endsWith(f, suffixes)) {
@@ -74,6 +75,22 @@ public class PropsUtils {
 		}
 	}
 
+	public static Props loadProps(Props parent, File ... propFiles) {
+		try {
+			Props props = new Props(parent);
+			for (File f: propFiles) {
+				if (f.isFile()) {
+					props = new Props(props, f);
+				}
+			}
+			
+			return props;
+		}
+		catch (IOException e) {
+			throw new RuntimeException("Error loading properties.", e);
+		}
+	}
+	
 	/**
 	 * Load job schedules from the given directories
 	 * 
@@ -185,10 +202,8 @@ public class PropsUtils {
 		parentProps.put("azkaban.flow.start.hour", loadTime.toString("HH"));
 		parentProps.put("azkaban.flow.start.minute", loadTime.toString("mm"));
 		parentProps.put("azkaban.flow.start.seconds", loadTime.toString("ss"));
-		parentProps.put("azkaban.flow.start.milliseconds",
-				loadTime.toString("SSS"));
-		parentProps.put("azkaban.flow.start.timezone",
-				loadTime.toString("ZZZZ"));
+		parentProps.put("azkaban.flow.start.milliseconds", loadTime.toString("SSS"));
+		parentProps.put("azkaban.flow.start.timezone", loadTime.toString("ZZZZ"));
 		return parentProps;
 	}
 
diff --git a/src/java/azkaban/webapp/AzkabanWebServer.java b/src/java/azkaban/webapp/AzkabanWebServer.java
index 01261a8..a11f8cb 100644
--- a/src/java/azkaban/webapp/AzkabanWebServer.java
+++ b/src/java/azkaban/webapp/AzkabanWebServer.java
@@ -26,6 +26,8 @@ import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Properties;
 import java.util.TimeZone;
@@ -448,9 +450,9 @@ public class AzkabanWebServer implements AzkabanServer {
 		
 		File viewerPluginPath = new File(pluginPath);
 		ClassLoader parentLoader = AzkabanWebServer.class.getClassLoader();
+		File[] pluginDirs = viewerPluginPath.listFiles();
 		ArrayList<String> jarPaths = new ArrayList<String>();
-		for (String plug: plugins) {
-			File pluginDir = new File(viewerPluginPath, plug);
+		for (File pluginDir: pluginDirs) {
 			if (!pluginDir.exists()) {
 				logger.error("Error viewer plugin path " + pluginDir.getPath() + " doesn't exist.");
 				continue;
@@ -465,7 +467,21 @@ public class AzkabanWebServer implements AzkabanServer {
 			File propertiesDir = new File(pluginDir, "conf");
 			Props pluginProps = null;
 			if (propertiesDir.exists() && propertiesDir.isDirectory()) {
-				pluginProps = PropsUtils.loadPropsInDir(propertiesDir, "properties");
+				File propertiesFile = new File(propertiesDir, "plugin.properties");
+				File propertiesOverrideFile = new File(propertiesDir, "override.properties");
+				
+				if (propertiesFile.exists()) {
+					if (propertiesOverrideFile.exists()) {
+						pluginProps = PropsUtils.loadProps(null, propertiesFile, propertiesOverrideFile);
+					}
+					else {
+						pluginProps = PropsUtils.loadProps(null, propertiesFile);
+					}
+				}
+				else {
+					logger.error("Plugin conf file " + propertiesFile + " not found.");
+					continue;
+				}
 			}
 			else {
 				logger.error("Plugin conf path " + propertiesDir + " not found.");
@@ -474,6 +490,10 @@ public class AzkabanWebServer implements AzkabanServer {
 			
 			String pluginName = pluginProps.getString("viewer.name");
 			String pluginWebPath = pluginProps.getString("viewer.path");
+			int pluginOrder = pluginProps.getInt("viewer.order", 0);
+			boolean pluginHidden = pluginProps.getBoolean("viewer.hidden", false);
+			List<String> extLibClasspath = pluginProps.getStringList("viewer.external.classpaths", (List<String>)null);
+			
 			String pluginClass = pluginProps.getString("viewer.servlet.class");
 			if (pluginClass == null) {
 				logger.error("Viewer class is not set.");
@@ -487,16 +507,28 @@ public class AzkabanWebServer implements AzkabanServer {
 			if (libDir.exists() && libDir.isDirectory()) {
 				File[] files = libDir.listFiles();
 				
-				URL[] url = new URL[files.length];
+				ArrayList<URL> urls = new ArrayList<URL>();
 				for (int i=0; i < files.length; ++i) {
 					try {
-						url[i] = files[i].toURI().toURL();
+						URL url = files[i].toURI().toURL();
+						urls.add(url);
 					} catch (MalformedURLException e) {
 						logger.error(e);
 					}
 				}
+				if (extLibClasspath != null) {
+					for (String extLib : extLibClasspath) {
+						try {
+							File file = new File(pluginDir, extLib);
+							URL url = file.toURI().toURL();
+							urls.add(url);
+						} catch (MalformedURLException e) {
+							logger.error(e);
+						}
+					}
+				}
 				
-				urlClassLoader = new URLClassLoader(url, parentLoader);
+				urlClassLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), parentLoader);
 			}
 			else {
 				logger.error("Library path " + propertiesDir + " not found.");
@@ -538,13 +570,22 @@ public class AzkabanWebServer implements AzkabanServer {
 			
 			AbstractAzkabanServlet avServlet = (AbstractAzkabanServlet)obj;
 			root.addServlet(new ServletHolder(avServlet), "/" + pluginWebPath + "/*");
-			installedViewerPlugins.add(new ViewerPlugin(pluginName, pluginWebPath));
+			installedViewerPlugins.add(new ViewerPlugin(pluginName, pluginWebPath, pluginOrder, pluginHidden));
 		}
 		
+		// Velocity needs the jar resource paths to be set.
 		String jarResourcePath = StringUtils.join(jarPaths, ", ");
 		logger.info("Setting jar resource path " + jarResourcePath);
 		ve.addProperty("jar.resource.loader.path", jarResourcePath);
 		
+		// Sort plugins based on order
+		Collections.sort(installedViewerPlugins, new Comparator<ViewerPlugin>() {
+			@Override
+			public int compare(ViewerPlugin o1, ViewerPlugin o2) {
+				return o1.getOrder() - o2.getOrder();
+			}
+		});
+		
 		return installedViewerPlugins;
 	}
 	
diff --git a/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java b/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java
index 9817b56..a2820d3 100644
--- a/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java
+++ b/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java
@@ -342,9 +342,9 @@ public abstract class AbstractAzkabanServlet extends HttpServlet {
 		//@TODO, allow more than one type of viewer. For time sake, I only install the first one
 		if (viewerPlugins != null && !viewerPlugins.isEmpty()) {
 			page.add("viewers", viewerPlugins);
-			ViewerPlugin plugin = viewerPlugins.get(0);
-			page.add("viewerName", plugin.getPluginName());
-			page.add("viewerPath", plugin.getPluginPath());
+//			ViewerPlugin plugin = viewerPlugins.get(0);
+//			page.add("viewerName", plugin.getPluginName());
+//			page.add("viewerPath", plugin.getPluginPath());
 		}
 		
 		return page;
diff --git a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index ab3fee0..77f48db 100644
--- a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -1068,12 +1068,14 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
 			String type = null;
 			
 			final String contentType = item.getContentType();
-			if(contentType.startsWith("application/zip")) {
+			if(contentType != null && (contentType.startsWith("application/zip") || contentType.startsWith("application/x-zip-compressed"))) {
 				type = "zip";
 			}
 			else {
 				item.delete();
 				setErrorMessageInCookie(resp, "File type " + contentType + " unrecognized.");
+				
+				return;
 			}
 			
 			File tempDir = Utils.createTempDir();
diff --git a/src/java/azkaban/webapp/servlet/velocity/nav.vm b/src/java/azkaban/webapp/servlet/velocity/nav.vm
index 2cc9206..8019467 100644
--- a/src/java/azkaban/webapp/servlet/velocity/nav.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/nav.vm
@@ -28,10 +28,12 @@
 				<li id="executing-jobs-tab" #if($current_page == 'executing')class="selected"#end onClick="navMenuClick('$!context/executor')"><a href="$!context/executor">Executing</a></li>
 				<li id="history-jobs-tab" #if($current_page == 'history')class="selected"#end onClick="navMenuClick('$!context/history')"><a href="$!context/history">History</a></li>
 				
-				#if ($viewers) 
-					<li id="viewer-tab" #if($current_page == 'viewer') class="selected"#end onClick="navMenuClick('$!context/$viewerPath')">
-						<a href="$!context/$viewerPath">$viewerName</a>
+				#foreach($viewer in $viewers)
+					#if(!$viewer.hidden)
+					<li #if($current_page == $viewer.pluginName) class="selected"#end onClick="navMenuClick('$!context/$viewer.pluginPath')">
+						<a href="$!context/$viewer.pluginPath">$viewer.pluginName</a>
 					</li>
+					#end
 				#end
 			</ul>
 			
diff --git a/src/java/azkaban/webapp/servlet/ViewerPlugin.java b/src/java/azkaban/webapp/servlet/ViewerPlugin.java
index 725473f..e54c4aa 100644
--- a/src/java/azkaban/webapp/servlet/ViewerPlugin.java
+++ b/src/java/azkaban/webapp/servlet/ViewerPlugin.java
@@ -3,10 +3,14 @@ package azkaban.webapp.servlet;
 public class ViewerPlugin {
 	private final String pluginName;
 	private final String pluginPath;
+	private final int order;
+	private boolean hidden;
 	
-	public ViewerPlugin(String pluginName, String pluginPath) {
+	public ViewerPlugin(String pluginName, String pluginPath, int order, boolean hidden) {
 		this.pluginName = pluginName;
 		this.pluginPath = pluginPath;
+		this.order = order;
+		this.setHidden(hidden);
 	}
 
 	public String getPluginName() {
@@ -16,4 +20,16 @@ public class ViewerPlugin {
 	public String getPluginPath() {
 		return pluginPath;
 	}
+
+	public int getOrder() {
+		return order;
+	}
+
+	public boolean isHidden() {
+		return hidden;
+	}
+
+	public void setHidden(boolean hidden) {
+		this.hidden = hidden;
+	}
 }