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    }