001 /****************************************************************************** 002 * Copyright (C) MActor Developers. All rights reserved. * 003 * ---------------------------------------------------------------------------* 004 * This file is part of MActor. * 005 * * 006 * MActor is free software; you can redistribute it and/or modify * 007 * it under the terms of the GNU General Public License as published by * 008 * the Free Software Foundation; either version 2 of the License, or * 009 * (at your option) any later version. * 010 * * 011 * MActor is distributed in the hope that it will be useful, * 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 014 * GNU General Public License for more details. * 015 * * 016 * You should have received a copy of the GNU General Public License * 017 * along with MActor; if not, write to the Free Software * 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * 019 ******************************************************************************/ 020 package org.mactor.framework.spec; 021 022 import java.io.BufferedReader; 023 import java.io.BufferedWriter; 024 import java.io.File; 025 import java.io.FileInputStream; 026 import java.io.FileOutputStream; 027 import java.io.FileReader; 028 import java.io.FileWriter; 029 import java.io.FilenameFilter; 030 import java.io.IOException; 031 import java.io.Reader; 032 import java.io.StringWriter; 033 import java.io.Writer; 034 import java.util.LinkedList; 035 import java.util.Properties; 036 037 import javax.xml.XMLConstants; 038 import javax.xml.transform.stream.StreamSource; 039 import javax.xml.validation.Schema; 040 import javax.xml.validation.SchemaFactory; 041 import javax.xml.validation.Validator; 042 043 import org.dom4j.Document; 044 import org.dom4j.io.OutputFormat; 045 import org.dom4j.io.SAXReader; 046 import org.dom4j.io.XMLWriter; 047 import org.mactor.framework.MactorException; 048 049 public class ProjectContext { 050 private File projectDir; 051 private File projectConfigDir; 052 private String globalConfigName; 053 private String messageBrokerConfigName; 054 private static ProjectContext instance; 055 private boolean dirty; 056 private static Object lock = new Object(); 057 public static ProjectContext getGlobalInstance() { 058 if (instance == null) { 059 synchronized (lock) { 060 if (instance == null) { 061 instance = new ProjectContext(); 062 } 063 } 064 } 065 return instance; 066 } 067 public String getProjectName() { 068 return projectDir.getName(); 069 } 070 private File getFileDir(boolean isConfigDir) { 071 if (isConfigDir) 072 return projectConfigDir; 073 return projectDir; 074 } 075 public File getAbsolutePath(String relativePath) { 076 try { 077 return new File(projectDir.getAbsolutePath() + "/" + relativePath).getCanonicalFile(); 078 } catch (IOException e) { 079 e.printStackTrace(); 080 return new File(projectDir.getAbsolutePath() + "/" + relativePath); 081 } 082 } 083 public String getRelativePath(File path) { 084 if (path == null) 085 return null; 086 File filePath = new File(path.getAbsolutePath()); 087 File fDir = null; 088 if (!filePath.isDirectory()) 089 fDir = filePath.getParentFile(); 090 else 091 fDir = new File(path.getAbsolutePath()); 092 // find first common dir 093 LinkedList<String> relativeSegments = new LinkedList<String>(); 094 int pDirDownCounter = 0; 095 boolean found = false; 096 while (fDir != null) { 097 pDirDownCounter = 0; 098 File pDir = new File(projectDir.getAbsolutePath()); 099 while (pDir != null) { 100 if (fDir.equals(pDir)) { 101 found = true; 102 break; 103 } 104 pDir = pDir.getParentFile(); 105 pDirDownCounter++; 106 } 107 if (found) 108 break; 109 relativeSegments.addFirst(fDir.getName()); 110 fDir = fDir.getParentFile(); 111 } 112 StringBuffer sb = new StringBuffer(""); 113 for (int i = 0; i < pDirDownCounter; i++) 114 sb.append("../"); 115 for (String seg : relativeSegments) 116 sb.append(seg).append("/"); 117 if (!path.isDirectory()) 118 sb.append(path.getName()); 119 return sb.toString(); 120 } 121 public Document readFromFile(String name, boolean isConfigFile) throws MactorException { 122 return readFromFile(new File(getFileDir(isConfigFile).getAbsolutePath() + "/" + name)); 123 } 124 public Document readFromFile(File path) throws MactorException { 125 if (path == null || !path.exists()) 126 throw new MactorException("The file '" + path + "' does not exist"); 127 SAXReader reader = new SAXReader(); 128 try { 129 final String sl = XMLConstants.W3C_XML_SCHEMA_NS_URI; 130 SchemaFactory factory = SchemaFactory.newInstance(sl); 131 StreamSource ss = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("mactor.xsd")); 132 Schema schema = factory.newSchema(ss); 133 Validator v = schema.newValidator(); 134 v.validate(new StreamSource(path)); 135 Document doc = reader.read(path); 136 return doc; 137 } catch (Exception e) { 138 throw new MactorException("Faile to parse file '" + path.getAbsolutePath() + "'. Error:" + e.getMessage(), e); 139 } 140 } 141 public void writeDocumentToFile(File file, Document doc) throws MactorException { 142 try { 143 OutputFormat format = OutputFormat.createPrettyPrint(); 144 FileWriter fw = new FileWriter(file); 145 XMLWriter xw = new XMLWriter(fw, format); 146 doc.normalize(); 147 xw.write(doc.getRootElement()); 148 xw.flush(); 149 fw.close(); 150 } catch (IOException ioe) { 151 throw new MactorException("Failed to write the file '" + file.getAbsolutePath() + "'. Error:" + ioe.getMessage(), ioe); 152 } 153 } 154 public File writeStringToFile(String name, String content, boolean isConfigFile) throws MactorException { 155 File path = new File(getFileDir(isConfigFile).getAbsolutePath() + "/" + name); 156 if (path.isDirectory()) 157 throw new MactorException("The file '" + path.getAbsolutePath() + "' is a directory"); 158 try { 159 FileWriter fw = new FileWriter(path); 160 fw.write(content); 161 fw.flush(); 162 fw.close(); 163 } catch (IOException ioe) { 164 throw new MactorException("Failed to write the file '" + path.getAbsolutePath() + "'. Error:" + ioe.getMessage(), ioe); 165 } 166 return path; 167 } 168 public String readStringFromFile(String name, boolean isConfigFile) throws MactorException { 169 File path = new File(getFileDir(isConfigFile).getAbsolutePath() + "/" + name); 170 if (!path.exists()) 171 return null; 172 if (path.isDirectory()) 173 throw new MactorException("The file '" + path.getAbsolutePath() + "' is a directory"); 174 try { 175 FileReader fr = new FileReader(path); 176 StringWriter out = new StringWriter(); 177 int c; 178 while ((c = fr.read()) != -1) { 179 out.write(c); 180 } 181 fr.close(); 182 return out.toString(); 183 } catch (IOException ioe) { 184 throw new MactorException("Failed to write the file '" + path.getAbsolutePath() + "'. Error:" + ioe.getMessage(), ioe); 185 } 186 } 187 public File renameFile(File oldFile, String newFilename) throws MactorException { 188 File currentFile = new File(oldFile.getAbsolutePath()); 189 File newFile = new File(oldFile.getParent() + "/" + newFilename); 190 if (!currentFile.renameTo(newFile)) 191 throw new MactorException("Failed to rename file '" + currentFile.getAbsolutePath() + "' to file '" + newFile.getAbsolutePath() + "'"); 192 return newFile; 193 } 194 public File duplicateFile(File file) throws MactorException { 195 File currentFile = new File(file.getAbsolutePath()); 196 File newFile = new File(file.getParent() + "/" + getNextFilename(file.getName(), file.getParentFile())); 197 try { 198 Reader in = new BufferedReader(new FileReader(currentFile)); 199 Writer out = new BufferedWriter(new FileWriter(newFile)); 200 int c; 201 while ((c = in.read()) != -1) { 202 out.write(c); 203 } 204 out.flush(); 205 in.close(); 206 out.close(); 207 return newFile; 208 } catch (IOException e) { 209 throw new MactorException("Failed to copy file '" + currentFile.getAbsolutePath() + "' to file '" + newFile.getAbsolutePath() + "'"); 210 } 211 } 212 public void deleteFile(File file) throws MactorException { 213 if (!file.delete()) 214 throw new MactorException("Unable to delete the file '" + file.getAbsolutePath() + "'"); 215 } 216 private static class CurrentFilesFilter implements FilenameFilter { 217 String name; 218 String ending; 219 CurrentFilesFilter(String name, String ending) { 220 this.name = name; 221 this.ending = ending; 222 } 223 public boolean accept(File dir, String fn) { 224 return fn.endsWith(ending) & fn.startsWith(name); 225 } 226 } 227 public String getNextFilename(String filename, boolean isConfigFile) { 228 return getNextFilename(filename, getFileDir(isConfigFile)); 229 } 230 private String getNextFilename(String filename, File dir) { 231 int endingIndex = filename.lastIndexOf("."); 232 String name = null; 233 String ending = ""; 234 if (endingIndex > 0) { 235 name = filename.substring(0, endingIndex); 236 ending = filename.substring(endingIndex, filename.length()); 237 } else { 238 name = filename; 239 } 240 int nextIndex = getNextIndex(dir, name, ending); 241 if (nextIndex == 0) 242 return filename; 243 return name + nextIndex + ending; 244 } 245 private int getNextIndex(File dir, String name, String ending) { 246 String[] filename = dir.list(new CurrentFilesFilter(name, ending)); 247 if (filename == null || filename.length == 0) 248 return 0; 249 int largest = 0; 250 for (int i = 0; i < filename.length; i++) { 251 String index = filename[i].substring(name.length()); 252 if (ending != null && ending.length() > 0) { 253 int n = index.lastIndexOf(ending); 254 if (n > 0) 255 index = index.substring(0, n); 256 } 257 try { 258 int n = Integer.parseInt(index); 259 if (n > largest) 260 largest = n; 261 } catch (NumberFormatException nfe) { 262 } 263 } 264 return largest + 1; 265 } 266 public File getProjectDir() { 267 return projectDir; 268 } 269 public File getProjectConfigDir() { 270 return projectConfigDir; 271 } 272 public void setProjectDir(File dir) { 273 projectDir = new File(dir.getAbsolutePath()); 274 loadProjectFile(); 275 } 276 public void setGlobalConfigName(String globalConfigName) { 277 this.globalConfigName = globalConfigName; 278 writeProjectFile(); 279 } 280 public void setMessageBrokerConfigName(String messageBrokerConfigName) { 281 this.messageBrokerConfigName = messageBrokerConfigName; 282 writeProjectFile(); 283 } 284 public void setProjectConfigDir(File projectConfigDir) { 285 this.projectConfigDir = projectConfigDir; 286 writeProjectFile(); 287 } 288 public GlobalConfig loadGlobalConfig() throws MactorException { 289 if (globalConfigName == null || globalConfigName.length() == 0) 290 return null; 291 return new GlobalConfig(readFromFile(globalConfigName, true)); 292 } 293 public MessageBrokersConfig loadMessageBrokersConfig() throws MactorException { 294 if (messageBrokerConfigName == null || messageBrokerConfigName.length() == 0) 295 return null; 296 return new MessageBrokersConfig(readFromFile(messageBrokerConfigName, true)); 297 } 298 private void writeProjectFile() { 299 File f = new File(projectDir.getAbsolutePath() + "/mactor.mproject"); 300 Properties projectProps = new Properties(); 301 projectProps.put("config_dir", getRelativePath(projectConfigDir)); 302 if (globalConfigName != null) 303 projectProps.put("global_config", globalConfigName); 304 if (messageBrokerConfigName != null) 305 projectProps.put("message_broker_config", messageBrokerConfigName); 306 try { 307 FileOutputStream fos = new FileOutputStream(f); 308 projectProps.store(fos, ""); 309 fos.close(); 310 } catch (IOException ioe) { 311 ioe.printStackTrace(); 312 } 313 } 314 private void loadProjectFile() { 315 File f = new File(projectDir.getAbsolutePath() + "/mactor.mproject"); 316 Properties projectProps = new Properties(); 317 try { 318 if (!f.exists()) { 319 FileWriter fw = new FileWriter(f); 320 fw.write("config_dir="); 321 fw.close(); 322 } 323 projectProps.load(new FileInputStream(f)); 324 } catch (IOException ioe) { 325 ioe.printStackTrace(); 326 } 327 String cd = projectProps.getProperty("config_dir"); 328 if (cd != null && cd.length() > 0) { 329 projectConfigDir = getAbsolutePath(cd); 330 } else { 331 projectConfigDir = new File(projectDir.getAbsolutePath()); 332 } 333 globalConfigName = projectProps.getProperty("global_config"); 334 messageBrokerConfigName = projectProps.getProperty("message_broker_config"); 335 } 336 public String getGlobalConfigName() { 337 return globalConfigName; 338 } 339 public String getMessageBrokerConfigName() { 340 return messageBrokerConfigName; 341 } 342 public boolean isDirty() { 343 return dirty; 344 } 345 public void setDirty(boolean dirty) { 346 this.dirty = dirty; 347 if (dirty && listener != null) 348 listener.onDirty(); 349 } 350 ProjectContextListener listener; 351 public interface ProjectContextListener { 352 void onDirty(); 353 } 354 public ProjectContextListener getListener() { 355 return listener; 356 } 357 public void setListener(ProjectContextListener listener) { 358 this.listener = listener; 359 } 360 }