azkaban-aplcache
Changes
src/java/azkaban/project/Project.java 75(+68 -7)
src/java/azkaban/user/Permission.java 131(+92 -39)
src/java/azkaban/utils/JSONUtils.java 89(+89 -0)
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
src/java/azkaban/project/Project.java 75(+68 -7)
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;
+ }
}
src/java/azkaban/user/Permission.java 131(+92 -39)
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;
+ }
}
src/java/azkaban/utils/JSONUtils.java 89(+89 -0)
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