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 }