/* * Copyright 2012 Michael Chang, Tai-Lin Chu, Artin Menachekanian, * Charles Rudolph, Eduard Sedakov, Suzanna Whiteside * * This file is part of ServerLibraryManager. * * ServerLibraryManager is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ServerLibraryManager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with ServerLibraryManager. If not, see <http://www.gnu.org/licenses/>. */ package edu.ucla.loni.server; import edu.ucla.loni.shared.*; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.sql.Timestamp; import java.util.Date; import java.util.List; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import org.jdom2.output.XMLOutputter; public class ServerUtils { //************************************************************ // File Operations //************************************************************ /** * Returns an unused absolute path built by combining the parameters and checking for conflicts * <p> Possible return values: * <br> root/packageName/type/name.pipe * <br> root/packageName/type/name_(2).pipe * <br> root/packageName/type/name_(3).pipe * <br> etc */ public static String newAbsolutePath(String root, String packageName, String type, String name){ String newAbsolutePath = root + File.separatorChar + packageName.replace(" " , "_") + File.separatorChar + type.replace(" " , "_") + File.separatorChar + name.replace(" " , "_") + ".pipe"; File file = new File(newAbsolutePath); if (!file.exists()){ return newAbsolutePath; } else { String testPathPart = newAbsolutePath.substring(0, newAbsolutePath.lastIndexOf(".pipe")); String ext = ".pipe"; for (int i = 2 ;; i++){ newAbsolutePath = testPathPart + "_(" + i + ")" + ext; file = new File(newAbsolutePath); if (!file.exists()){ return newAbsolutePath; } } } } /** * Removes directory if it empty and its parent folder if that becomes empty * @param dir a file that is a directory */ public static void removeEmptyDirectory(File dir){ if(dir.listFiles().length == 0) { dir.delete(); File parent = dir.getParentFile(); if (parent.listFiles().length == 0){ parent.delete(); } } } //************************************************************ // XML //************************************************************ //------------------------------------------------------------ // Read //------------------------------------------------------------ /** * Parse an XML file into a Document */ public static Document readXML(File pipe) throws Exception{ SAXBuilder builder = new SAXBuilder(); Document doc = (Document) builder.build(pipe); return doc; } /** * Parse an XML file into a Document */ public static Document readXML(InputStream stream) throws Exception{ SAXBuilder builder = new SAXBuilder(); Document doc = (Document) builder.build(stream); return doc; } //------------------------------------------------------------ // Write //------------------------------------------------------------ /** * Write a document (XML file) to a particular absolute path * @throws Exception */ public static void writeXML(File file, Document doc) throws Exception{ XMLOutputter xmlOut = new XMLOutputter(); FileOutputStream fileOut = new FileOutputStream(file); xmlOut.output(doc, fileOut); fileOut.flush(); fileOut.close(); } //------------------------------------------------------------ // Parse (getChildrenText and getMainElement are helpers) //------------------------------------------------------------ /** * Get the text value of children joined by separator */ private static String getChildrenText(Element element, String childName, String separator){ List<Element> children = element.getChildren(childName); int length = children.size(); String ret = ""; for (int i = 0; i < length; i++){ Element child = children.get(i); String text = child.getText(); if (text != ""){ ret += text + separator; } } // Remove the last separator if (ret != ""){ ret = ret.substring(0, ret.length() - separator.length()); } return ret; } /** * Get the main element (who has the attributes and children we care about) * from a document */ private static Element getMainElement(Document doc) throws Exception{ Element pipeline = doc.getRootElement(); Element moduleGroup = pipeline.getChild("moduleGroup"); if (moduleGroup == null){ throw new Exception("Pipefile does not have moduleGroup"); } else { List<Element> data = moduleGroup.getChildren("dataModule"); List<Element> module = moduleGroup.getChildren("module"); if (data.size() == 1 && module.size() == 0){ return data.get(0); } else if (module.size() == 1 && data.size() == 0) { return module.get(0); } else { return moduleGroup; } } } /** * Parses a .pipe into a Pipefile */ public static Pipefile parseXML(Document doc){ try { Pipefile pipe = new Pipefile(); Element main = getMainElement(doc); String mainName = main.getName(); if (mainName.equals("dataModule")){ pipe.type = "Data"; } else if (mainName.equals("module")){ pipe.type = "Modules"; } else if (mainName.equals("moduleGroup")){ pipe.type = "Groups"; } else { throw new Exception("Pipefile has unknown type"); } // General Properties pipe.name = main.getAttributeValue("name", ""); pipe.packageName = main.getAttributeValue("package", ""); pipe.description = main.getAttributeValue("description", ""); pipe.tags = getChildrenText(main, "tag", ","); // Get type specific properties if (pipe.type.equals("Data")){ Element values = main.getChild("values"); if (values != null){ pipe.values = getChildrenText(values, "value", "\n"); } Element output = main.getChild("output"); if (output != null){ Element format = output.getChild("format"); if (format != null){ pipe.formatType = format.getAttributeValue("type"); } } } if (pipe.type.equals("Modules")){ pipe.location = main.getAttributeValue("location", ""); } if (pipe.type.equals("Modules") || pipe.type.equals("Groups")){ pipe.uri = main.getChildText("uri"); } return pipe; } catch (Exception e){ return null; } } public static Pipefile parseXML(File file){ try { Document doc = readXML(file); Pipefile pipe = parseXML(doc); if (pipe != null){ pipe.absolutePath = file.getAbsolutePath(); } return pipe; } catch (Exception e){ return null; } } //------------------------------------------------------------ // Update //------------------------------------------------------------ /** * Updates a Document (XML file) with all the attributes from a Pipefile * @throws Exception */ public static Document updateXML(Document doc, Pipefile pipe) throws Exception{ Element main = getMainElement(doc); // Update name (attribute) main.setAttribute("name", pipe.name); // Update package (attribute) main.setAttribute("package", pipe.packageName); // Update description (attribute) main.setAttribute("description", pipe.description); // Update the tags (children) main.removeChildren("tag"); // Remove all old tags String tags = pipe.tags; if (tags != null && tags.length() > 0){ String[] tagArray = tags.split(","); for (String tag : tagArray){ Element child = new Element("tag"); child.setText(tag); main.addContent(child); } } if (pipe.type.equals("Data")){ // Update values (values child => children) Element valuesElement = main.getChild("values"); if (valuesElement == null){ valuesElement = new Element("values"); main.addContent(valuesElement); } valuesElement.removeChildren("value"); // Remove all old values String values = pipe.values; if (values != null && values.length() > 0){ String[] valueArray = values.split("\n"); for (String value : valueArray){ Element valueElement = new Element("value"); valueElement.setText(value); valuesElement.addContent(valueElement); } } // Update formatType (output child => format child => attribute) Element output = main.getChild("output"); if (output == null){ output = new Element("output"); main.addContent(output); } Element format = output.getChild("format"); if (format == null){ format = new Element("format"); main.addContent(format); } format.setAttribute("type", pipe.formatType); } if (pipe.type.equals("Modules")){ // Update location (attribute) main.setAttribute("location", pipe.location); } if (pipe.type.equals("Modules") || pipe.type.equals("Groups")){ // Update uri (child) Element uri = main.getChild("uri"); // If child not present, create if (uri == null){ uri = new Element("uri"); main.addContent(uri); } uri.setText(pipe.uri); } return doc; } //************************************************************ // Monitor File //************************************************************ private static String monitorRelativePath = ".monitorfile"; //------------------------------------------------------------ // Get //------------------------------------------------------------ private static File getMonitorFile(Directory dir){ return new File(dir.absolutePath + File.separator + monitorRelativePath); } public static Timestamp getMonitorFileModified(Directory dir){ Timestamp ret = null; File monitorFile = ServerUtils.getMonitorFile(dir); if (monitorFile.exists()){ ret = new Timestamp(monitorFile.lastModified()); } return ret; } //------------------------------------------------------------ // Touch //------------------------------------------------------------ public static void touchMonitorFile(Directory dir) throws Exception{ // Current time Date now = new Date(); File monitor = getMonitorFile(dir); monitor.setLastModified( now.getTime() ); // Update the database dir.monitorModified = new Timestamp(monitor.lastModified()); Database.updateDirectory(dir); } //************************************************************ // Access File //************************************************************ private static String accessRelativePath = ".access.xml"; //------------------------------------------------------------ // Get //------------------------------------------------------------ private static File getAccessFile(Directory dir){ return new File(dir.absolutePath + File.separator + accessRelativePath); } public static Timestamp getAccessFileModified(Directory dir){ Timestamp ret = null; File accessFile = ServerUtils.getAccessFile(dir); if (accessFile.exists()){ ret = new Timestamp(accessFile.lastModified()); } return ret; } //------------------------------------------------------------ // Read (readAccessFileGroup is a helper) //------------------------------------------------------------ public static String readAccessFileGroup(Element parentEle){ String rs = ""; String sep = ","; for (Element agent: parentEle.getChildren()){ String agentName = agent.getValue(); String groupAttr = agent.getAttributeValue("group"); boolean isGroup = groupAttr.equals("true"); if (isGroup){ agentName = GroupSyntax.groupnameToAgent(agentName); } rs += agentName + sep; } if (!rs.equals("")){ // Get rid of final separator rs = rs.substring(0, rs.length() - sep.length()); } return rs; } /** * Reads the access file for the root directory * Side Effect: Updates accessFileModified in the database */ public static void readAccessFile(Directory root) throws Exception { File accessFile = ServerUtils.getAccessFile(root); if (!accessFile.exists()){ return; } Document doc = readXML(accessFile); Element access = doc.getRootElement(); Element filesRoot = access.getChild("files"); Element groupsRoot = access.getChild("groups"); if (filesRoot.getChildren() != null) { for (Element pipe: filesRoot.getChildren()){ String packageName = pipe.getAttributeValue("package"); String type = pipe.getAttributeValue("type"); String name = pipe.getAttributeValue("name"); Pipefile thisPipe = Database.selectPipefileByHierarchy(root.dirId, packageName, type, name); if (thisPipe != null){ thisPipe.access = readAccessFileGroup(pipe);; Database.updatePipefile(thisPipe); } } } if (groupsRoot.getChildren() != null) { for (Element group: groupsRoot.getChildren()) { String name = group.getAttributeValue("name"); String userString = readAccessFileGroup(group); Group thisGroup = Database.selectGroupByName(root.dirId, name); if (thisGroup == null){ thisGroup = new Group(); thisGroup.name = name; thisGroup.users = userString; Database.insertGroup(root.dirId, thisGroup); } else { thisGroup.users = userString; Database.updateGroup(thisGroup); } } } // Update when the access file was written root.accessModified = new Timestamp( accessFile.lastModified() ); Database.updateDirectory(root); } //------------------------------------------------------------ // Write (agentElement is a helper) //------------------------------------------------------------ /** * Creates an agent Element */ public static Element agentElement(String agent){ agent = agent.trim(); String value, group; if (GroupSyntax.isGroup(agent)){ value = GroupSyntax.agentToGroupname(agent); group = "true"; } else { value = agent; group = "false"; } return new Element("agent").addContent(value).setAttribute("group", group); } /** * Writes the access file for the root directory * Side Effect: Updates accessFileModified in the database */ public static void writeAccessFile(Directory root) throws Exception{ File accessFile = getAccessFile(root); if (!accessFile.exists()){ boolean success = accessFile.createNewFile(); if (!success){ throw new Exception ("Could not create access file"); } } // <files> Element filesRoot = new Element("files"); // For each pipe, add a <file> child to <files> Pipefile[] pipes = Database.selectPipefiles(root.dirId); if (pipes != null){ for(Pipefile p : pipes) { // Only add the pipefile if access is not empty if (!p.access.equals("")){ Element file = new Element("file"); file.setAttribute("type", p.type); file.setAttribute("name", p.name); file.setAttribute("package", p.packageName); // Add agents String[] agents = p.access.split(","); for (String agent : agents) { if (!agent.equals("")){ file.addContent(agentElement(agent)); } } filesRoot.addContent(file); } } } // <groups> Element groupsRoot = new Element("groups"); // For each group, add a <group> child to <groups> Group[] groups = Database.selectGroups(root.dirId); if (groups != null){ for(Group g : groups) { Element group = new Element("group"); group.setAttribute("name", g.name); // Add agents String[] agents = g.users.split(","); for (String agent : agents) { if (!agent.equals("")){ group.addContent(agentElement(agent)); } } groupsRoot.addContent(group); } } // Root Element Element access = new Element("access"); access.addContent(filesRoot); access.addContent(groupsRoot); // Document Document doc = new Document(); doc.addContent(access); // Write document writeXML(accessFile, doc); // Update when the access file was written root.accessModified = new Timestamp( accessFile.lastModified() ); Database.updateDirectory(root); } }