001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.him.editors;
020:
021: import java.io.*;
022: import java.util.*;
023:
024: import org.openharmonise.him.harmonise.*;
025: import org.openharmonise.vfs.*;
026: import org.openharmonise.vfs.context.*;
027: import org.openharmonise.vfs.status.*;
028:
029: /**
030: * The editor controller is the external interface to the editor
031: * architecture. It makes the decisions about which {@link org.openharmonise.him.editors.Editor}
032: * is applicable for a virtual file, manages workfing file and monitors them for
033: * changes.
034: *
035: * @author Matthew Large
036: * @version $Revision: 1.2 $
037: *
038: */
039: public class EditorController implements ContextListener {
040:
041: /**
042: * Map of full paths to {@link FileDetails} objects.
043: */
044: private HashMap m_VirtualPhysicalMapping = new HashMap();
045:
046: /**
047: * Instance of editor controller, follows singleton pattern.
048: */
049: private static EditorController m_instance = null;
050:
051: /**
052: *
053: */
054: private EditorController() {
055: super ();
056: FileMonitor fm = new FileMonitor(1000 * 5);
057: fm.start();
058: ContextHandler.getInstance().addListener(
059: ContextType.CONTEXT_SHUTDOWN, this );
060: }
061:
062: /**
063: * Returns the instance of the editor controller, follows the
064: * singleton pattern.
065: *
066: * @return Instance
067: */
068: public static EditorController getInstance() {
069: if (m_instance == null) {
070: m_instance = new EditorController();
071: }
072: return m_instance;
073: }
074:
075: /**
076: * Opens a virtual file for editing.
077: *
078: * @param sPath Full path
079: * @param vfs Virtual file system
080: */
081: public StatusData open(String sPath, AbstractVirtualFileSystem vfs) {
082: StatusData status = new VFSStatus();
083:
084: Editor editor = this .getEditor(sPath, vfs);
085: if (editor != null) {
086: PathStatusWrapper pathStatus = editor.open(sPath, vfs);
087: String sRealPath = pathStatus.getPath();
088: status = pathStatus.getStatus();
089: if (sRealPath != null) {
090: File fFile = new File(sRealPath);
091: long modified = fFile.lastModified();
092: FileDetails details = new FileDetails(sRealPath, sPath,
093: vfs, editor);
094: details.setModified(modified);
095: this .m_VirtualPhysicalMapping.put(sPath, details);
096: }
097: }
098:
099: return status;
100: }
101:
102: /**
103: * Opens a virtual file for previewing.
104: *
105: * @param sPath Full path
106: * @param vfs Virtual file system
107: */
108: public StatusData preview(String sPath,
109: AbstractVirtualFileSystem vfs) {
110: StatusData status = new VFSStatus();
111:
112: Editor editor = this .getEditor(sPath, vfs);
113: if (editor != null) {
114: PathStatusWrapper pathStatus = editor.preview(sPath, vfs);
115: String sRealPath = pathStatus.getPath();
116: status = pathStatus.getStatus();
117: if (sRealPath != null) {
118: File fFile = new File(sRealPath);
119: }
120: }
121:
122: return status;
123: }
124:
125: /**
126: * Exports the content of a virtual file.
127: *
128: * @param sPath Full path
129: * @param vfs Virtual file system
130: */
131: public StatusData export(String sPath, AbstractVirtualFileSystem vfs) {
132: StatusData status = new VFSStatus();
133:
134: Editor editor = this .getEditor(sPath, vfs);
135: if (editor != null) {
136: status = editor.export(sPath, vfs);
137: }
138:
139: return status;
140: }
141:
142: /**
143: * Creates a new virtual file.
144: *
145: * @param sPath Full path
146: * @param vfs Virtual file system
147: * @return true if the resource was actually created
148: */
149: public StatusData createNew(String sPath,
150: AbstractVirtualFileSystem vfs) {
151: StatusData status = new VFSStatus();
152:
153: Editor editor = this .getEditor(sPath, vfs);
154: if (editor != null) {
155: PathStatusWrapper pathStatus = editor.createNew(sPath, vfs);
156: String sRealPath = pathStatus.getPath();
157: status = pathStatus.getStatus();
158: if (sRealPath != null) {
159: File fFile = new File(sRealPath);
160: long modified = fFile.lastModified();
161: FileDetails details = new FileDetails(sRealPath, sPath,
162: vfs, editor);
163: details.setModified(modified);
164: this .m_VirtualPhysicalMapping.put(sPath, details);
165: }
166: if (!editor.hasResourceBeenCreated()) {
167: status.setStatusLevel(StatusData.LEVEL_ERROR);
168: System.err.println("Editor says resource NOT created.");
169: } else {
170: System.err.println("Editor says resource WAS created.");
171: }
172: return status;
173: }
174: status.setStatusLevel(StatusData.LEVEL_ERROR);
175: return status;
176: }
177:
178: /**
179: * Creates a new virtual file.
180: *
181: * @param sPath Full path
182: * @param content Content for new virtual file
183: * @param vfs Virtual file system
184: * @return true if the resource was actually created
185: */
186: public StatusData createNew(String sPath, byte[] content,
187: AbstractVirtualFileSystem vfs) {
188: StatusData status = new VFSStatus();
189:
190: Editor editor = this .getEditor(sPath, vfs);
191: if (editor != null) {
192: PathStatusWrapper pathStatus = editor.createNew(sPath,
193: content, vfs);
194: String sRealPath = pathStatus.getPath();
195: status = pathStatus.getStatus();
196: if (sRealPath != null) {
197: File fFile = new File(sRealPath);
198: long modified = fFile.lastModified();
199: FileDetails details = new FileDetails(sRealPath, sPath,
200: vfs, editor);
201: details.setModified(modified);
202: this .m_VirtualPhysicalMapping.put(sPath, details);
203: }
204: if (!editor.hasResourceBeenCreated()) {
205: status.setStatusLevel(StatusData.LEVEL_ERROR);
206: System.err.println("Editor says resource NOT created.");
207: } else {
208: System.err.println("Editor says resource WAS created.");
209: }
210: return status;
211: }
212: status.setStatusLevel(StatusData.LEVEL_ERROR);
213: return status;
214: }
215:
216: /**
217: * Discards any changes that have been made to a virtual file's
218: * content.
219: *
220: * @param sPath Full path
221: * @param vfs Virtual file system
222: */
223: public StatusData discardChanges(String sPath,
224: AbstractVirtualFileSystem vfs) {
225: StatusData status = new VFSStatus();
226:
227: Editor editor = this .getEditor(sPath, vfs);
228: if (editor != null) {
229: status = editor.discardChanges(sPath, vfs);
230: }
231: return status;
232: }
233:
234: /**
235: * @param fullPath
236: * @param vfs
237: */
238: public StatusData upload(String sPath, AbstractVirtualFileSystem vfs) {
239: StatusData status = new VFSStatus();
240:
241: Editor editor = this .getEditor(sPath, vfs);
242: if (editor != null) {
243: PathStatusWrapper pathStatus = editor.upload(sPath, vfs);
244: String sRealPath = pathStatus.getPath();
245: status = pathStatus.getStatus();
246: if (sRealPath != null) {
247: File fFile = new File(sRealPath);
248: long modified = fFile.lastModified();
249: FileDetails details = new FileDetails(sRealPath, sPath,
250: vfs, editor);
251: details.setModified(modified);
252: this .m_VirtualPhysicalMapping.put(sPath, details);
253: }
254: }
255: return status;
256: }
257:
258: /**
259: * Returns an editor appropriate to the given path and virtual file
260: * system.
261: *
262: * @param sPath Full path
263: * @param vfs Virtual file system
264: * @return Editor or null if none found
265: */
266: private Editor getEditor(String sPath, AbstractVirtualFileSystem vfs) {
267: Editor editor = null;
268:
269: editor = this .getLiveEditor(sPath, vfs);
270: if (editor == null) {
271: editor = this .getNoneLiveEditor(sPath, vfs);
272: if (editor == null) {
273: }
274: }
275:
276: return editor;
277: }
278:
279: /**
280: * Returns an editor appropriate to the given live path and virtual file
281: * system.
282: *
283: * @param sPath Full path
284: * @param vfs Virtual file system
285: * @return Editor or null if none found
286: */
287: private Editor getLiveEditor(String sPath,
288: AbstractVirtualFileSystem vfs) {
289:
290: Editor editor = null;
291: if (sPath.startsWith(HarmonisePaths.PATH_DOCUMENTS)) {
292: editor = new XMetaLEditor();
293: } else if (sPath.startsWith(HarmonisePaths.PATH_NEWSLETTER)) {
294: editor = new XMetaLEditor();
295: } else if (sPath.startsWith(HarmonisePaths.PATH_COMPOSITION)) {
296: editor = new CompositionEditor();
297: } else if (sPath.startsWith(HarmonisePaths.PATH_XSLT)) {
298: editor = new XSLTEditor();
299: } else if (sPath
300: .startsWith(HarmonisePaths.PATH_PAGE_DEFINITION)) {
301: editor = new PageDefinitionEditor();
302: } else if (sPath.startsWith(HarmonisePaths.PATH_LINKS)
303: || sPath.startsWith(HarmonisePaths.PATH_EMAIL)) {
304: editor = new LinkEditor();
305: } else if (sPath.startsWith(HarmonisePaths.PATH_USERS)) {
306: editor = new UserEditor();
307: } else if (sPath
308: .startsWith(HarmonisePaths.PATH_REPORTS_QUERIES)) {
309: editor = new SystemReportEditor();
310: } else if (sPath.startsWith(HarmonisePaths.PATH_REPORTS_OUTPUT)) {
311: editor = new SystemReportOutputEditor();
312: } else if (sPath.startsWith(HarmonisePaths.PATH_WORKFLOW_PROPS)
313: || sPath
314: .startsWith(HarmonisePaths.PATH_WORKFLOW_STAGES)) {
315: editor = new WorkflowEditor();
316: } else if (sPath.startsWith(HarmonisePaths.PATH_METADATA)
317: || sPath.startsWith(HarmonisePaths.PATH_RBS_PROPS)
318: || sPath.startsWith(HarmonisePaths.PATH_RBS_VALS)
319: || sPath.startsWith(HarmonisePaths.PATH_RBS_PROPS)
320: || sPath.startsWith(HarmonisePaths.PATH_RBS_PROPS)) {
321: editor = new BlankEditor();
322: }
323:
324: return editor;
325: }
326:
327: /**
328: * Returns an editor appropriate to the given none live path and virtual file
329: * system.
330: *
331: * @param sPath Full path
332: * @param vfs Virtual file system
333: * @return Editor or null if none found
334: */
335: private Editor getNoneLiveEditor(String sPath,
336: AbstractVirtualFileSystem vfs) {
337: Editor editor = null;
338:
339: VirtualFile vfFile = vfs.getVirtualFile(sPath).getResource();
340: if (vfFile != null
341: && (vfFile.getState() == VirtualFile.STATE_PENDING || vfFile
342: .getState() == VirtualFile.STATE_HISTORICAL)
343: && ((VersionedVirtualFile) vfFile).getLiveVersionPath() != null) {
344: sPath = ((VersionedVirtualFile) vfFile)
345: .getLiveVersionPath();
346: } else if (vfFile != null
347: && (vfFile.getState() == VirtualFile.STATE_PENDING || vfFile
348: .getState() == VirtualFile.STATE_HISTORICAL)
349: && ((VersionedVirtualFile) vfFile).getLiveVersionPath() == null) {
350: }
351: editor = this .getLiveEditor(sPath, vfs);
352: if (editor == null) {
353: editor = new FileAssetEditor();
354: }
355: return editor;
356: }
357:
358: /**
359: * Checks all current working files for changes to their modification
360: * date. If changes are found the content of the working file is
361: * copied into the virtual file.
362: *
363: */
364: protected void checkFiles() {
365: if (this .m_VirtualPhysicalMapping.size() > 0) {
366: Iterator itor = this .m_VirtualPhysicalMapping.values()
367: .iterator();
368: while (itor.hasNext()) {
369: FileDetails details = (FileDetails) itor.next();
370: String sRealPath = details.getRealPath();
371: File fFile = new File(sRealPath);
372: long modified = fFile.lastModified();
373:
374: if (modified > details.getModified()) {
375: VirtualFile vfFile = details.getVFS()
376: .getVirtualFile(details.getVirtualPath())
377: .getResource();
378:
379: if (details.getEditor() instanceof XMetaLEditor) {
380: Long lFileLength = new Long(fFile.length());
381: byte[] byteContents = new byte[lFileLength
382: .intValue()];
383: char[] chars = new char[1];
384:
385: StringBuffer sBuffContent = new StringBuffer();
386:
387: FileInputStream fis = null;
388: InputStreamReader isr = null;
389: try {
390: fis = new FileInputStream(fFile);
391: isr = new InputStreamReader(fis, "UTF-8");
392:
393: char tempChar = ' ';
394: int nByte = isr.read(chars);
395:
396: while (nByte != -1) {
397: sBuffContent.append(chars);
398: nByte = isr.read(chars);
399: }
400:
401: try {
402: vfFile.setContent(sBuffContent
403: .toString().trim().getBytes(
404: "UTF-8"));
405: } catch (Exception e) {
406: e.printStackTrace();
407: vfFile.setContent(sBuffContent
408: .toString().trim().getBytes());
409: }
410:
411: details.setModified(modified);
412: } catch (Exception e2) {
413: e2.printStackTrace(System.out);
414: } finally {
415: try {
416: isr.close();
417: fis.close();
418: } catch (Exception e3) {
419: e3.printStackTrace(System.out);
420: }
421: }
422: } else {
423: Long lFileLength = new Long(fFile.length());
424: byte[] byteContents = new byte[lFileLength
425: .intValue()];
426:
427: FileInputStream fis = null;
428: try {
429: fis = new FileInputStream(fFile);
430: fis.read(byteContents);
431: vfFile.setContent(byteContents);
432:
433: details.setModified(modified);
434: } catch (Exception e2) {
435: e2.printStackTrace(System.out);
436: } finally {
437: try {
438: fis.close();
439: } catch (Exception e3) {
440: e3.printStackTrace(System.out);
441: }
442: }
443: }
444: }
445: }
446: }
447: }
448:
449: /**
450: * Checks if a file contains validly parsable XML.
451: *
452: * @param file File to check
453: * @return true if the file contains validly parsable XML
454: */
455: private boolean isValidXML(File file) {
456: boolean bValid = true;
457:
458: return bValid;
459: }
460:
461: /**
462: * Returns the file details for a specified working file path.
463: *
464: * @param sRealPath Local path
465: * @return File details or null if none found
466: */
467: private FileDetails getDetails(String sRealPath) {
468: FileDetails details = null;
469:
470: Iterator itor = this .m_VirtualPhysicalMapping.values()
471: .iterator();
472: while (itor.hasNext()) {
473: FileDetails element = (FileDetails) itor.next();
474: if (element.getRealPath().equalsIgnoreCase(sRealPath)) {
475: details = element;
476: }
477: }
478:
479: return details;
480: }
481:
482: /**
483: * Wrapper for the details about a virtual file and its' local
484: * working file.
485: *
486: * @author Matthew Large
487: * @version $Revision: 1.2 $
488: *
489: */
490: class FileDetails {
491:
492: /**
493: * Path to local working file.
494: */
495: private String m_sRealPath = null;
496:
497: /**
498: * Full path to virtual file.
499: */
500: private String m_sVirtualPath = null;
501:
502: /**
503: * Virtual file system.
504: */
505: private AbstractVirtualFileSystem m_vfs = null;
506:
507: /**
508: * Last recorded modified date for working file.
509: */
510: private long m_lModified = 0;
511:
512: /**
513: * Editor used for this resoruce.
514: */
515: private Editor m_editor = null;
516:
517: /**
518: * Constructs a new file details object.
519: *
520: * @param sRealPath Path to local working file
521: * @param sVirtualPath Full path to virtual file
522: * @param vfs Virtual file system
523: * @param editor Editor used for this resource
524: */
525: public FileDetails(String sRealPath, String sVirtualPath,
526: AbstractVirtualFileSystem vfs, Editor editor) {
527: super ();
528: this .m_sRealPath = sRealPath;
529: this .m_sVirtualPath = sVirtualPath;
530: this .m_vfs = vfs;
531: this .m_editor = editor;
532: }
533:
534: /**
535: * Returns the editor used for this resource.
536: *
537: * @return Editor
538: */
539: public Editor getEditor() {
540: return this .m_editor;
541: }
542:
543: /**
544: * Returns the path to the local working resource.
545: *
546: * @return Path
547: */
548: public String getRealPath() {
549: return this .m_sRealPath;
550: }
551:
552: /**
553: * Returns the full path to the virtual file.
554: *
555: * @return Full path
556: */
557: public String getVirtualPath() {
558: return this .m_sVirtualPath;
559: }
560:
561: /**
562: * Returns the virtual file system.
563: *
564: * @return Virtual file system
565: */
566: public AbstractVirtualFileSystem getVFS() {
567: return this .m_vfs;
568: }
569:
570: /**
571: * Returns the last recorded modified date for the local
572: * working file.
573: *
574: * @return Modified date
575: */
576: public long getModified() {
577: return this .m_lModified;
578: }
579:
580: /**
581: * Sets the modified date for the local working file.
582: *
583: * @param lModified Modified date
584: */
585: public void setModified(long lModified) {
586: this .m_lModified = lModified;
587: }
588: }
589:
590: /**
591: * Thread to monitor the working files for changes.
592: *
593: * @author Matthew Large
594: * @version $Revision: 1.2 $
595: *
596: */
597: class FileMonitor extends Thread {
598:
599: /**
600: * Sleep time in milliseconds.
601: */
602: private long sleepTime;
603:
604: /**
605: * Constructs a new file monitor thread.
606: *
607: * @param sleepTime Sleep time in milliseconds
608: */
609: FileMonitor(long sleepTime) {
610: this .sleepTime = sleepTime;
611: }
612:
613: /* (non-Javadoc)
614: * @see java.lang.Runnable#run()
615: */
616: public void run() {
617: while (true) {
618: try {
619: sleep(sleepTime);
620: } catch (InterruptedException e) {
621: // ignore it
622: }
623:
624: EditorController.getInstance().checkFiles();
625: }
626: }
627: }
628:
629: /* (non-Javadoc)
630: * @see com.simulacramedia.contentmanager.context.ContextListener#contextMessage(com.simulacramedia.contentmanager.context.ContextEvent)
631: */
632: public void contextMessage(ContextEvent ce) {
633: if (ce.CONTEXT_TYPE == ContextType.CONTEXT_SHUTDOWN) {
634: this .clearTempDir();
635: }
636: }
637:
638: /**
639: * Clears the directory containing the local working files.
640: *
641: */
642: public void clearTempDir() {
643: File fTempDir = new File("C:\\ContentManager\\temp");
644: this .deleteDirContents(fTempDir);
645: }
646:
647: /**
648: * Deletes the contents of a local directory.
649: *
650: * @param fDir Directory to have contents deleted
651: */
652: private void deleteDirContents(File fDir) {
653: File[] children = fDir.listFiles();
654: for (int i = 0; i < children.length; i++) {
655: File file = children[i];
656: if (file.isDirectory()) {
657: this .deleteDirContents(file);
658: }
659: file.delete();
660: }
661: }
662:
663: public boolean isMonitoringVirtualFile(VirtualFile vfFile) {
664: boolean bRetn = false;
665: if (vfFile != null
666: && this .m_VirtualPhysicalMapping.keySet().contains(
667: vfFile.getFullPath())) {
668: bRetn = true;
669: }
670: return bRetn;
671: }
672:
673: public String getRealPath(VirtualFile vfFile) {
674: String sRealPath = null;
675:
676: FileDetails details = (FileDetails) this.m_VirtualPhysicalMapping
677: .get(vfFile.getFullPath());
678: if (details != null) {
679: sRealPath = details.getRealPath();
680: }
681:
682: return sRealPath;
683: }
684:
685: }
|