azkaban-aplcache

Removing Project loaders and merging them back into the ProjectManager,

5/10/2012 6:27:36 PM

Details

diff --git a/src/java/azkaban/project/FileProjectManager.java b/src/java/azkaban/project/FileProjectManager.java
index 315cb0b..d876e58 100644
--- a/src/java/azkaban/project/FileProjectManager.java
+++ b/src/java/azkaban/project/FileProjectManager.java
@@ -1,13 +1,18 @@
 package azkaban.project;
 
 import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.log4j.Logger;
 
+import azkaban.user.Permission;
+import azkaban.user.Permission.Type;
 import azkaban.user.User;
+import azkaban.utils.JSONUtils;
 import azkaban.utils.Props;
 
 /**
@@ -17,12 +22,15 @@ import azkaban.utils.Props;
  */
 public class FileProjectManager implements ProjectManager {
 	public static final String DIRECTORY_PARAM = "file.project.loader.path";
+	private static final String PROPERTIES_FILENAME = "project.json";
     private static final Logger logger = Logger.getLogger(FileProjectManager.class);
     private ConcurrentHashMap<String, Project> projects = new ConcurrentHashMap<String, Project>();
+
 	private File projectDirectory;
 	
     public FileProjectManager(Props props) {
     	setupDirectories(props);
+    	loadAllProjects();
     }
 
     private void setupDirectories(Props props) {
@@ -43,6 +51,35 @@ public class FileProjectManager implements ProjectManager {
     	}
     }
     
+    private void loadAllProjects() {
+    	File[] directories = projectDirectory.listFiles();
+    	
+    	for (File dir: directories) {
+    		if (!dir.isDirectory()) {
+    			logger.error("ERROR loading project from " + dir.getPath() + ". Not a directory." );
+    		}
+    		else {
+    			File propertiesFile = new File(dir, PROPERTIES_FILENAME);
+    			if (!propertiesFile.exists()) {
+        			logger.error("ERROR loading project from " + dir.getPath() + ". Project file " + PROPERTIES_FILENAME + " not found." );
+    			}
+    			else {
+    				Object obj = null;
+    				try {
+    					obj = JSONUtils.parseJSONFromFile(propertiesFile);
+					} catch (IOException e) {
+						logger.error("ERROR loading project from " + dir.getPath() + ". Project file " + PROPERTIES_FILENAME + " couldn't be read.", e );
+						continue;
+					}
+    				
+    				Project project = Project.projectFromObject(obj);
+    				logger.info("Loading project " + project.getName());
+    				projects.put(project.getName(), project);
+    			}
+    		}
+    	}
+    }
+    
     public List<String> getProjectNames() {
         return new ArrayList<String>(projects.keySet());
     }
@@ -67,17 +104,59 @@ public class FileProjectManager implements ProjectManager {
     		throw new ProjectManagerException("Project already exists.");
     	}
     	
+    	File projectPath = new File(projectDirectory, projectName);
+    	if (projectPath.exists()) {
+    		throw new ProjectManagerException("Project already exists.");
+    	}
+    	
+    	if(!projectPath.mkdirs()) {
+    		throw new ProjectManagerException(
+    				"Project directory " + projectName + 
+    				" cannot be created in " + projectDirectory);
+    	}
+    	
+    	Permission perm = new Permission(Type.ADMIN);
+    	long time = System.currentTimeMillis();
+    	
     	Project project = new Project(projectName);
+    	project.setUserPermission(creator.getUserId(), perm);
+    	project.setDescription(description);
+    	project.setCreateTimestamp(time);
+    	project.setLastModifiedTimestamp(time);
+    	
+    	logger.info("Trying to create " + project.getName() + " by user " + creator.getUserId());
+    	try {
+			writeProjectFile(projectPath, project);
+		} catch (IOException e) {
+    		throw new ProjectManagerException(
+    				"Project directory " + projectName + 
+    				" cannot be created in " + projectDirectory, e);
+		}
+    	
     	return project;
     }
     
-    public Project loadProjects() {
-    	return null;
+    private void writeProjectFile(File directory, Project project) throws IOException {
+    	Object object = project.toObject();
+    	File outputFile = new File(directory, PROPERTIES_FILENAME);
+    	logger.info("Writing project file " + outputFile);
+    	String output = JSONUtils.toJSON(object, true);
+    	
+    	FileWriter writer = new FileWriter(outputFile);
+    	try {
+    		writer.write(output);
+    	} catch (IOException e) {
+    		if (writer != null) {
+    			writer.close();
+    		}
+    		
+    		throw e;
+    	}
+    	writer.close();
     }
 
 	@Override
 	public synchronized Project removeProjects(String projectName) {
-		// TODO Auto-generated method stub
 		return null;
 	}
 }
\ No newline at end of file
diff --git a/src/java/azkaban/project/Project.java b/src/java/azkaban/project/Project.java
index 24ed79e..18eb498 100644
--- a/src/java/azkaban/project/Project.java
+++ b/src/java/azkaban/project/Project.java
@@ -19,7 +19,7 @@ public class Project {
         this.name = name;
     }
 
-    public String getName() {
+	public String getName() {
         return name;
     }
     
@@ -31,8 +31,8 @@ public class Project {
     	return description;
     }
     
-    public void setUserPermission(String userid, Permission flags) {
-    	userToPermission.put(userid, flags);
+    public void setUserPermission(String userid, Permission perm) {
+    	userToPermission.put(userid, perm);
     }
     
     public Permission getUserPermission(User user) {
@@ -79,8 +79,9 @@ public class Project {
     	Map<String,Object> projectObject = (Map<String,Object>)object;
     	String name = (String)projectObject.get("name");
     	String description = (String)projectObject.get("description");
-    	long createTimestamp = (Long)projectObject.get("createTimestamp");
-    	long lastModifiedTimestamp =  (Long)projectObject.get("lastModifiedTimestamp");
+    	
+    	long createTimestamp = coerceToLong(projectObject.get("createTimestamp"));
+    	long lastModifiedTimestamp = coerceToLong(projectObject.get("lastModifiedTimestamp"));
     	
     	Project project = new Project(name);
     	project.setDescription(description);
@@ -94,11 +95,71 @@ public class Project {
     		String userid = (String)user.get("userid");
     		Permission perm = new Permission();
     		List<String> list = (List<String>)user.get("permissions");
-    		perm.setPermissions(list);
+    		perm.setPermissionsByName(list);
     		
     		project.setUserPermission(userid, perm);
     	}
     	
-    	return null;
+    	return project;
+    }
+    
+    private static long coerceToLong(Object obj) {
+    	if (obj == null) {
+    		return 0;
+    	}
+    	else if (obj instanceof Integer) {
+    		return (Integer)obj;
+    	}
+    	
+    	return (Long)obj;
     }
+    
+    @Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ (int) (createTimestamp ^ (createTimestamp >>> 32));
+		result = prime * result
+				+ ((description == null) ? 0 : description.hashCode());
+		result = prime
+				* result
+				+ (int) (lastModifiedTimestamp ^ (lastModifiedTimestamp >>> 32));
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		result = prime
+				* result
+				+ ((userToPermission == null) ? 0 : userToPermission.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Project other = (Project) obj;
+		if (createTimestamp != other.createTimestamp)
+			return false;
+		if (description == null) {
+			if (other.description != null)
+				return false;
+		} else if (!description.equals(other.description))
+			return false;
+		if (lastModifiedTimestamp != other.lastModifiedTimestamp)
+			return false;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		if (userToPermission == null) {
+			if (other.userToPermission != null)
+				return false;
+		} else if (!userToPermission.equals(other.userToPermission))
+			return false;
+		return true;
+	}
 }
diff --git a/src/java/azkaban/user/Permission.java b/src/java/azkaban/user/Permission.java
index 81e95de..dfa99dc 100644
--- a/src/java/azkaban/user/Permission.java
+++ b/src/java/azkaban/user/Permission.java
@@ -2,71 +2,124 @@ package azkaban.user;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.HashSet;
+import java.util.Set;
 
 public class Permission {
-	public static final String[] PERMISSIONS = {"READ", "WRITE", "EXECUTE", "SCHEDULE", "DELETE", "ADMIN"};
-	private static final Map<String, Integer> PERMISSIONS_TO_INDEX = new HashMap<String,Integer>();
+	public enum Type {
+		READ,
+		WRITE,
+		EXECUTE,
+		SCHEDULE,
+		DELETE,
+		ADMIN
+	}
+
+	private Set<Type> permissions = new HashSet<Type>();
 	
-	static {
-		int i = 0;
-		for (String perm: PERMISSIONS) {
-			PERMISSIONS_TO_INDEX.put(perm, i++);
-		}
+	public Permission() {
 	}
 	
-	private boolean[] flags;
+	public Permission(Type ... list) {
+		setPermission(list);
+	}
 	
-	public Permission() {
-		flags = new boolean[PERMISSIONS.length];
+	public void setPermission(Type ... list) {
+		for (Type perm: list) {
+			permissions.add(perm);
+		}
 	}
 	
-	public void setPermissions(String ... list) {
+	public void setPermissionsByName(String ... list) {
 		for (String perm: list) {
-			Integer index = PERMISSIONS_TO_INDEX.get(perm);
-			if (index != null) {
-				flags[index] = true;
-			}
+			Type type = Type.valueOf(perm);
+			if (type != null) {
+				permissions.add(type);
+			};
 		}
 	}
 	
-	public void setPermissions(Collection<String> list) {
-		for (String perm: list) {
-			Integer index = PERMISSIONS_TO_INDEX.get(perm);
-			if (index != null) {
-				flags[index] = true;
-			}
+	public void setPermissions(Collection<Type> list) {
+		for (Type perm: list) {
+			permissions.add(perm);
 		}
 	}
 	
-	public void unsetPermissions(String ... list) {
+	public void setPermissionsByName(Collection<String> list) {
 		for (String perm: list) {
-			Integer index = PERMISSIONS_TO_INDEX.get(perm);
-			if (index != null) {
-				flags[index] = false;
-			}
+			Type type = Type.valueOf(perm);
+			if (type != null) {
+				permissions.add(type);
+			};
 		}
 	}
 	
-	public boolean isPermissionSet(String permission) {
-		Integer index = PERMISSIONS_TO_INDEX.get(permission);
-		if (index != null) {
-			return flags[index];
+	public void unsetPermissions(Type ... list) {
+		for (Type perm: list) {
+			permissions.remove(perm);
 		}
-
-		return false;
+	}
+	
+	public void unsetPermissionsByName(String ... list) {
+		for (String perm: list) {
+			Type type = Type.valueOf(perm);
+			if (type != null) {
+				permissions.remove(type);
+			};
+		}
+	}
+	
+	public boolean isPermissionSet(Type permission) {
+		return permissions.contains(permission);
+	}
+	
+	public boolean isPermissionNameSet(String permission) {
+		return permissions.contains(Type.valueOf(permission));
 	}
 	
 	public String[] toStringArray() {
 		ArrayList<String> list = new ArrayList<String>();
 		int count = 0;
-		for (int i = 0; i < flags.length; ++i) {
-			if (flags[i]) {
-				list.add(PERMISSIONS[i]);
-				count++;
-			}
+		for (Type type: permissions) {
+			list.add(type.toString());
+			count++;
 		}
 		return list.toArray(new String[count]);
 	}
+	
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		for (Type perm: permissions) {
+			buffer.append(perm.toString());
+			buffer.append(",");
+		}
+		
+		return buffer.toString();
+	}
+	
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((permissions == null) ? 0 : permissions.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Permission other = (Permission) obj;
+		if (permissions == null) {
+			if (other.permissions != null)
+				return false;
+		} else if (!permissions.equals(other.permissions))
+			return false;
+		return true;
+	}
 }
diff --git a/src/java/azkaban/utils/JSONUtils.java b/src/java/azkaban/utils/JSONUtils.java
index 46bec48..028ff2e 100644
--- a/src/java/azkaban/utils/JSONUtils.java
+++ b/src/java/azkaban/utils/JSONUtils.java
@@ -1,6 +1,19 @@
 package azkaban.utils;
 
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParser;
 import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.codehaus.jackson.node.ObjectNode;
 
 public class JSONUtils {
 	/**
@@ -10,11 +23,87 @@ public class JSONUtils {
 	}
 	
 	public static String toJSON(Object obj) {
+		return toJSON(obj, false);
+	}
+	
+	public static String toJSON(Object obj, boolean prettyPrint) {
 		ObjectMapper mapper = new ObjectMapper();
+
 		try {
+			if (prettyPrint) {
+				ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter();
+				return writer.writeValueAsString(obj);
+			}
 			return mapper.writeValueAsString(obj);
 		} catch (Exception e) {
 			throw new RuntimeException(e);
 		}
 	}
+	
+	public static Object parseJSONFromString(String json) throws IOException {
+		ObjectMapper mapper = new ObjectMapper();
+    	JsonFactory factory = new JsonFactory();
+    	JsonParser parser = factory.createJsonParser(json);
+		JsonNode node = mapper.readTree(parser);
+		
+		return toObjectFromJSONNode(node);
+	}
+	
+	public static Object parseJSONFromFile(File file) throws IOException {
+		ObjectMapper mapper = new ObjectMapper();
+    	JsonFactory factory = new JsonFactory();
+    	JsonParser parser = factory.createJsonParser(file);
+		JsonNode node = mapper.readTree(parser);
+		
+		return toObjectFromJSONNode(node);
+	}
+	
+	private static Object toObjectFromJSONNode(JsonNode node) {
+		if (node.isObject()) {
+			HashMap<String, Object> obj = new HashMap<String,Object>();
+			Iterator<String> iter = node.getFieldNames();
+			while (iter.hasNext()) {
+				String fieldName = iter.next();
+				JsonNode subNode = node.get(fieldName);
+				Object subObj = toObjectFromJSONNode(subNode);
+				obj.put(fieldName, subObj);
+			}
+			
+			return obj;
+		}
+		else if (node.isArray()) {
+			ArrayList<Object> array = new ArrayList<Object>();
+			Iterator<JsonNode> iter = node.getElements();
+			while (iter.hasNext()) {
+				JsonNode element = iter.next();
+				Object subObject = toObjectFromJSONNode(element);
+				array.add(subObject);
+			}
+			return array;
+		}
+		else if (node.isTextual()) {
+			return node.asText();
+		}
+		else if (node.isNumber()) {
+			if (node.isInt()) {
+				return node.asInt();
+			}
+			else if (node.isLong()) {
+				return node.asLong();
+			}
+			else if (node.isDouble()) {
+				return node.asDouble();
+			}
+			else {
+				System.err.println("ERROR What is this!? " + node.getNumberType());
+				return null;
+			}
+		}
+		else if (node.isBoolean()) {
+			return node.asBoolean();
+		}
+		else {
+			return null;
+		}
+	}
 }
diff --git a/src/java/azkaban/webapp/AzkabanWebServer.java b/src/java/azkaban/webapp/AzkabanWebServer.java
index 150a962..1f3605f 100644
--- a/src/java/azkaban/webapp/AzkabanWebServer.java
+++ b/src/java/azkaban/webapp/AzkabanWebServer.java
@@ -35,9 +35,7 @@ import org.mortbay.jetty.servlet.DefaultServlet;
 import org.mortbay.jetty.servlet.ServletHolder;
 import org.mortbay.thread.QueuedThreadPool;
 
-import azkaban.project.FileProjectLoader;
 import azkaban.project.FileProjectManager;
-import azkaban.project.ProjectLoader;
 import azkaban.project.ProjectManager;
 import azkaban.user.UserManager;
 import azkaban.user.XmlUserManager;
@@ -297,7 +295,7 @@ public class AzkabanWebServer {
         }
         AzkabanWebServer app = new AzkabanWebServer(azkabanSettings);
 
-        int portNumber = azkabanSettings.getInt("jetty.port",DEFAULT_PORT_NUMBER);
+        //int portNumber = azkabanSettings.getInt("jetty.port",DEFAULT_PORT_NUMBER);
         int sslPortNumber = azkabanSettings.getInt("jetty.ssl.port",DEFAULT_SSL_PORT_NUMBER);
         int maxThreads = azkabanSettings.getInt("jetty.maxThreads",DEFAULT_THREAD_NUMBER);
 
diff --git a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index 2f52bbd..569462f 100644
--- a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -59,7 +59,7 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
     	logger.info("Create project " + projectName);
     	
     	User user = session.getUser();
-
+    	
     	String status = null;
     	String action = null;
     	String message = null;
diff --git a/unit/java/azkaban/test/project/ProjectTest.java b/unit/java/azkaban/test/project/ProjectTest.java
new file mode 100644
index 0000000..7f48a8b
--- /dev/null
+++ b/unit/java/azkaban/test/project/ProjectTest.java
@@ -0,0 +1,31 @@
+package azkaban.test.project;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import azkaban.project.Project;
+import azkaban.user.Permission;
+import azkaban.user.Permission.Type;
+import azkaban.utils.JSONUtils;
+
+public class ProjectTest {
+    @Test
+    public void testToAndFromObject() throws Exception {
+    	Project project = new Project("tesTing");
+    	project.setCreateTimestamp(1l);
+    	project.setLastModifiedTimestamp(2l);
+    	project.setDescription("I am a test");
+    	project.setUserPermission("user1", new Permission(new Type[]{Type.ADMIN, Type.DELETE}));
+    	
+    	Object obj = project.toObject();
+    	String json = JSONUtils.toJSON(obj);
+    	
+    	Object jsonObj = JSONUtils.parseJSONFromString(json);
+
+    	Project parsedProject = Project.projectFromObject(jsonObj);
+    	
+    	assertTrue(project.equals(parsedProject));
+    }
+
+}
diff --git a/unit/java/azkaban/test/user/PermissionTest.java b/unit/java/azkaban/test/user/PermissionTest.java
new file mode 100644
index 0000000..df1dd72
--- /dev/null
+++ b/unit/java/azkaban/test/user/PermissionTest.java
@@ -0,0 +1,91 @@
+package azkaban.test.user;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import azkaban.user.Permission;
+import azkaban.user.Permission.Type;
+
+public class PermissionTest {
+    @Before
+    public void setUp() throws Exception {
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+    }
+    
+    @Test
+    public void testEmptyPermissionCreation() throws Exception {
+    	Permission permission = new Permission();
+    	permission.setPermissionsByName(new String[]{});
+    }
+    
+    @Test
+    public void testSinglePermissionCreation() throws Exception {
+    	Permission perm1 = new Permission();
+    	perm1.setPermissionsByName("READ");
+    	
+    	Permission perm2 = new Permission();
+    	perm2.setPermission(Type.READ);
+    	info("Compare " + perm1.toString() + " and " + perm2.toString());
+    	assertTrue(perm1.equals(perm2));
+    }
+
+    @Test
+    public void testListPermissionCreation() throws Exception {
+    	Permission perm1 = new Permission();
+    	perm1.setPermissionsByName(new String[]{"READ", "EXECUTE"});
+    	
+    	Permission perm2 = new Permission();
+    	perm2.setPermission(new Type[]{Type.EXECUTE, Type.READ});
+    	info("Compare " + perm1.toString() + " and " + perm2.toString());
+    	assertTrue(perm1.equals(perm2));
+    }
+    
+    @Test
+    public void testRemovePermission() throws Exception {
+    	Permission perm1 = new Permission();
+    	perm1.setPermissionsByName(new String[]{"READ", "EXECUTE", "WRITE"});
+    	perm1.unsetPermissions(Type.EXECUTE);
+    	
+    	Permission perm2 = new Permission();
+    	perm2.setPermission(new Type[]{Type.READ, Type.WRITE});
+    	info("Compare " + perm1.toString() + " and " + perm2.toString());
+    	assertTrue(perm1.equals(perm2));
+    }
+    
+    @Test
+    public void testRemovePermissionByName() throws Exception {
+    	Permission perm1 = new Permission();
+    	perm1.setPermissionsByName(new String[]{"READ", "EXECUTE", "WRITE"});
+    	perm1.unsetPermissionsByName("EXECUTE");
+    	
+    	Permission perm2 = new Permission();
+    	perm2.setPermission(new Type[]{Type.READ, Type.WRITE});
+    	info("Compare " + perm1.toString() + " and " + perm2.toString());
+    	assertTrue(perm1.equals(perm2));
+    }
+    
+    @Test
+    public void testToAndFromObject() throws Exception {
+    	Permission permission = new Permission();
+    	permission.setPermissionsByName(new String[]{"READ", "EXECUTE", "WRITE"});
+    	
+    	String[] array = permission.toStringArray();
+    	Permission permission2 = new Permission();
+    	permission2.setPermissionsByName(array);
+    	assertTrue(permission.equals(permission2));
+    }
+    
+    /**
+     * Why? because it's quicker.
+     * @param message
+     */
+    public void info(String message) {
+    	System.out.println(message);
+    }
+}
\ No newline at end of file