001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.collab.channel.filesharing.filehandler;
042:
043: import com.sun.collablet.CollabException;
044:
045: import org.openide.cookies.EditorCookie;
046: import org.openide.filesystems.*;
047: import org.openide.loaders.*;
048: import org.openide.nodes.Node;
049:
050: import java.io.*;
051:
052: import java.util.*;
053:
054: import javax.swing.SwingUtilities;
055:
056: import org.netbeans.modules.collab.channel.filesharing.FilesharingConstants;
057: import org.netbeans.modules.collab.channel.filesharing.FilesharingContext;
058: import org.netbeans.modules.collab.channel.filesharing.eventlistener.FilesharingTimerTask;
059: import org.netbeans.modules.collab.channel.filesharing.filesystem.CollabFilesystem;
060: import org.netbeans.modules.collab.channel.filesharing.msgbean.SendFileData;
061: import org.netbeans.modules.collab.channel.filesharing.ui.*;
062: import org.netbeans.modules.collab.channel.filesharing.util.FileshareUtil;
063: import org.netbeans.modules.collab.core.Debug;
064:
065: /**
066: * SharedFileGroup
067: *
068: * @author ayub.khan@sun.com
069: * @version 1.0
070: */
071: public class SharedFileGroup extends Object implements
072: FilesharingConstants {
073: ////////////////////////////////////////////////////////////////////////////
074: // Constants
075: ////////////////////////////////////////////////////////////////////////////
076: public final static int UNKNOWN_TYPE = -1;
077: public final static int JAVA_TYPE = 1;
078: public final static int FORM_TYPE = 2;
079:
080: ////////////////////////////////////////////////////////////////////////////
081: // Instance variables
082: ////////////////////////////////////////////////////////////////////////////
083: private String fileGroupName;
084: private int fileGroupType = UNKNOWN_TYPE;
085: private String user;
086: private String projectName;
087: private SharedFileGroupManager manager = null;
088: private FilesharingContext context = null;
089: private List fileNames = new ArrayList();
090: private boolean isValid = true;
091: private boolean isSpecialFile = false;
092: private FileLock fileLock = null;
093: private EditorCookie cookie = null;
094: private Node projectNode = null;
095:
096: /**
097: *
098: * @param fileGroupName
099: * @param user
100: * @param manager
101: */
102: public SharedFileGroup(String fileGroupName, String user,
103: String projectName, SharedFileGroupManager manager) {
104: super ();
105: this .fileGroupName = fileGroupName;
106: this .user = user;
107: this .projectName = projectName;
108: this .manager = manager;
109: }
110:
111: ////////////////////////////////////////////////////////////////////////////
112: // methods
113: ////////////////////////////////////////////////////////////////////////////
114:
115: /**
116: *
117: * @return
118: */
119: public String getName() {
120: return this .fileGroupName;
121: }
122:
123: /**
124: *
125: * @return
126: */
127: public int getType() {
128: return this .fileGroupType;
129: }
130:
131: /**
132: *
133: * @param
134: */
135: public void setType(int type) {
136: this .fileGroupType = type;
137: }
138:
139: /**
140: *
141: * @return
142: */
143: public String getUser() {
144: return this .user;
145: }
146:
147: /**
148: *
149: * @param user
150: */
151: public void setUser(String newUser) {
152: this .user = newUser;
153: }
154:
155: /**
156: *
157: * @return
158: */
159: public String getProjectName() {
160: return this .projectName;
161: }
162:
163: /**
164: *
165: * @return cookie
166: */
167: public EditorCookie getEditorCookie() {
168: return this .cookie;
169: }
170:
171: /**
172: *
173: * @param cookie
174: */
175: public void setEditorCookie(EditorCookie cookie) {
176: this .cookie = cookie;
177: }
178:
179: /**
180: *
181: * @param searchFileName
182: * @return
183: */
184: public boolean contains(String searchFileName) {
185: return fileNames.contains(searchFileName);
186: }
187:
188: /**
189: *
190: * @param fileName
191: */
192: public void addFileHandler(CollabFileHandler fileHandler)
193: throws CollabException {
194: if ((fileHandler == null) || (fileHandler.getName() == null)) {
195: throw new CollabException("Filename or FileHandler null"); //NoI18n
196: }
197:
198: if (!fileNames.contains(fileHandler.getName())) {
199: this .fileNames.add(fileHandler.getName());
200: }
201:
202: manager.addFileHandler(fileHandler);
203: }
204:
205: /**
206: *
207: * @return fileHandlers
208: */
209: public CollabFileHandler[] getFileHandlers() {
210: List result = new ArrayList();
211:
212: for (int i = 0; i < fileNames.size(); i++) {
213: CollabFileHandler fileHandler = manager
214: .getFileHandler((String) fileNames.get(i));
215:
216: if (fileHandler != null) {
217: result.add(fileHandler);
218: }
219: }
220:
221: return (CollabFileHandler[]) result
222: .toArray(new CollabFileHandler[0]);
223: }
224:
225: /**
226: *
227: * @return fileHandler
228: */
229: public CollabFileHandler getFileHandler(FileObject fileObject)
230: throws CollabException {
231: List result = new ArrayList();
232:
233: for (int i = 0; i < fileNames.size(); i++) {
234: CollabFileHandler fileHandler = manager
235: .getFileHandler((String) fileNames.get(i));
236:
237: if ((fileHandler != null)
238: && (fileObject == fileHandler.getFileObject())) {
239: return fileHandler;
240: }
241: }
242:
243: return null;
244: }
245:
246: /**
247: * setValid
248: *
249: * @param status
250: * @throws CollabException
251: */
252: public void setValid(boolean valid) throws CollabException {
253: this .isValid = valid;
254: }
255:
256: /**
257: * getValid
258: *
259: * @return status if false handler is invalid
260: * @throws CollabException
261: */
262: public boolean isValid() throws CollabException {
263: return this .isValid;
264: }
265:
266: /**
267: * createFileHandler
268: *
269: * @param fileGroupName
270: * @param fileObject
271: * @return collabFileHandler
272: */
273: public CollabFileHandler createFileHandler(
274: final FilesharingContext context, final String fileOwner,
275: final String projectName, final String fileName,
276: final FileObject fileObject, final EditorCookie cookie)
277: throws CollabException {
278: CollabFileHandler collabFileHandler = doCreateFileHandler(
279: fileName, fileObject, false, cookie);
280:
281: if (collabFileHandler == null) {
282: return null;
283: }
284:
285: boolean sendFirstTime = collabFileHandler.isSendFirstTime();
286:
287: if ((collabFileHandler.getCurrentState() == FilesharingContext.STATE_SENDFILE)
288: || (collabFileHandler.getCurrentState() == FilesharingContext.STATE_RECEIVEDSENDFILE)) {
289: Debug.log("CollabFileHandlerSupport",
290: "CollabFileHandlerSupport, " + "current State: "
291: + collabFileHandler.getCurrentState()); //NoI18n
292:
293: return null;
294: }
295:
296: if (sendFirstTime) {
297: collabFileHandler.setFileGroup(this );
298: collabFileHandler.setFileObject(fileObject);
299:
300: //add file owner
301: context.addFileOwner(fileOwner);
302:
303: //Add file to owner map for file annotations
304: context.addToFileOwnerMap(fileName);
305:
306: try {
307: manager.addToOwnerSharedFile(getName(), projectName,
308: collabFileHandler);
309: } catch (CollabException ce) {
310: Debug.log("SendFileHandler", "SendFileHandler, " + //NoI18n
311: "addToOwnerSharedFile failed"); //NoI18n
312: Debug.logDebugException("SendFileHandler, " + //NoI18n
313: "addToOwnerSharedFile failed", //NoI18n
314: ce, true);
315:
316: return null;
317: }
318: }
319:
320: //reset state
321: collabFileHandler
322: .setCurrentState(FilesharingContext.STATE_UNKNOWN);
323:
324: return collabFileHandler;
325: }
326:
327: /**
328: *
329: * @param fileName
330: * @param contentType
331: * @throws CollabException
332: * @return
333: */
334: public CollabFileHandler createFileHandler(String fileName,
335: String fileContentType) throws CollabException {
336: CollabFileHandler collabFileHandler = manager
337: .getFileHandler(fileName);
338:
339: //Create an instance of CollabFileHandler
340: if (collabFileHandler == null) {
341: if (fileContentType == null) {
342: //throw new CollabException("Unknown Content Type");
343: return null;
344: }
345:
346: Debug.log(this , "FilesharingContext, contentType: " + //NoI18n
347: fileContentType + " for file: " + fileName); //NoI18n
348:
349: CollabFileHandlerFactory collabFileHandlerFactory = CollabFileHandlerResolver
350: .getDefault().resolve(fileContentType,
351: FileshareUtil.getFileExt(fileName));
352:
353: Debug.log(this ,
354: "FilesharingContext, collabFileHandlerFactory: " + //NoI18n
355: collabFileHandlerFactory.getID());
356:
357: if ((collabFileHandlerFactory != null)
358: && collabFileHandlerFactory instanceof CollabDefaultFileHandlerFactory) {
359: if ((fileContentType != null)
360: && fileContentType
361: .trim()
362: .equals(
363: CollabTextFileHandlerFactory.TEXT_MIME_TYPE)) {
364: collabFileHandlerFactory = new CollabTextFileHandlerFactory();
365: } else {
366: Debug.log(this ,
367: "FilesharingContext, contentType null"); //NoI18n
368: }
369: }
370:
371: if (collabFileHandlerFactory != null) {
372: collabFileHandler = collabFileHandlerFactory
373: .createCollabFileHandler();
374:
375: if (fileName.startsWith(FILE_SEPERATOR)) {
376: collabFileHandler
377: .setFileName(fileName.substring(1));
378: } else {
379: collabFileHandler.setFileName(fileName);
380: }
381:
382: collabFileHandler.setFileGroup(this );
383: collabFileHandler.setContext(getContext());
384:
385: if (collabFileHandlerFactory instanceof CollabTextFileHandlerFactory) {
386: String tmpcontentType = CollabTextFileHandlerFactory.TEXT_MIME_TYPE;
387:
388: if ((tmpcontentType == null)
389: || ((tmpcontentType != null) && !tmpcontentType
390: .trim()
391: .equals(
392: CollabTextFileHandlerFactory.TEXT_MIME_TYPE))) {
393: Debug
394: .log(
395: this ,
396: "FilesharingContext, setting contentType: "
397: + //NoI18n
398: CollabTextFileHandlerFactory.TEXT_MIME_TYPE);
399:
400: /*collabFileHandler.setContentType(
401: CollabTextFileHandlerFactory.TEXT_MIME_TYPE);*/
402: }
403: }
404:
405: addFileHandler(collabFileHandler);
406: } else {
407: throw new CollabException(
408: "No CollabFileHandlerFactory matches for "
409: + "Content Type: " + fileContentType);
410: }
411: }
412:
413: return collabFileHandler;
414: }
415:
416: /**
417: *
418: * @param fileName
419: * @param fileObject
420: * @param skip Change FileHandler Type
421: * @param cookie
422: * @throws CollabException
423: * @return
424: */
425: private CollabFileHandler doCreateFileHandler(String fileName,
426: final FileObject fileObject, boolean skipChangeFHType,
427: EditorCookie cookie) throws CollabException {
428: String contentType = fileObject.getMIMEType();
429:
430: if (fileName == null) {
431: fileName = ((CollabFilesystem) getContext()
432: .getCollabFilesystem()).getPath(fileObject);
433: }
434:
435: CollabFileHandler collabFileHandler = manager
436: .getFileHandler(fileName);
437:
438: //Create an instance of CollabFileHandler
439: if ((collabFileHandler == null) && (fileObject != null)) {
440: Debug.log(this , "FilesharingContext, contentType: " + //NoI18n
441: contentType); //NoI18n
442:
443: String fileExt = fileObject.getExt();
444: Debug.log(this , "FilesharingContext, fileExt: " + //NoI18n
445: fileExt); //NoI18n
446:
447: CollabFileHandlerFactory collabFileHandlerFactory = CollabFileHandlerResolver
448: .getDefault().resolve(contentType, fileExt);
449: Debug.log(this ,
450: "FilesharingContext, filehandler resolved to: " + //NoI18n
451: collabFileHandlerFactory.getID()); //NoI18n
452:
453: if (!skipChangeFHType
454: && (collabFileHandlerFactory != null)
455: && collabFileHandlerFactory instanceof CollabDefaultFileHandlerFactory
456: && !fileExt.equals("class")) {
457: if (cookie != null) {
458: collabFileHandlerFactory = new CollabTextFileHandlerFactory();
459: isSpecialFile = true; //if rename fails we can do special processing
460:
461: final String newFileName = fileObject.getNameExt();
462:
463: try {
464: FileSystem fs = getContext()
465: .getCollabFilesystem();
466: fs
467: .runAtomicAction(new FileSystem.AtomicAction() {
468: public void run()
469: throws IOException {
470: try {
471: fileLock = fileObject
472: .lock();
473:
474: //fileObject.rename(fileLock, newFileName, "txt");
475: isSpecialFile = false;
476: Debug
477: .log(
478: this ,
479: "FilesharingContext, "
480: + //NoI18n
481: "file rename from: "
482: + newFileName
483: + " to: "
484: + fileObject
485: .getNameExt()); //NoI18n
486: } catch (FileAlreadyLockedException ale) {
487: Debug
488: .log(
489: this ,
490: "FilesharingContext, "
491: + //NoI18n
492: "file rename failed for: "
493: + newFileName); //NoI18n
494: Debug
495: .logDebugException(
496: "FilesharingContext, "
497: + //NoI18n
498: "file rename failed for: "
499: + newFileName, //NoI18n
500: ale, true);
501: }
502: }
503: });
504: } catch (FileStateInvalidException ex) {
505: Debug.log(this , "FilesharingContext, "
506: + //NoI18n
507: "file rename failed for: "
508: + newFileName); //NoI18n
509: Debug.logDebugException("FilesharingContext, "
510: + //NoI18n
511: "file rename failed for: "
512: + newFileName, //NoI18n
513: ex, true);
514: } catch (IOException ex) {
515: Debug.log(this , "FilesharingContext, "
516: + //NoI18n
517: "file rename failed for: "
518: + newFileName); //NoI18n
519: Debug.logDebugException("FilesharingContext, "
520: + //NoI18n
521: "file rename failed for: "
522: + newFileName, //NoI18n
523: ex, true);
524: } catch (Exception ex) {
525: Debug.log(this , "FilesharingContext, "
526: + //NoI18n
527: "file rename failed for: "
528: + newFileName); //NoI18n
529: Debug.logDebugException("FilesharingContext, "
530: + //NoI18n
531: "file rename failed for: "
532: + newFileName, //NoI18n
533: ex, true);
534: } finally {
535: if (fileLock != null) {
536: fileLock.releaseLock();
537: }
538: }
539: } else {
540: Debug.log(this , "FilesharingContext, cookie null"); //NoI18n
541: }
542: }
543:
544: if (collabFileHandlerFactory != null) {
545: collabFileHandler = collabFileHandlerFactory
546: .createCollabFileHandler();
547:
548: if (fileName.startsWith(FILE_SEPERATOR)) {
549: collabFileHandler
550: .setFileName(fileName.substring(1));
551: } else {
552: collabFileHandler.setFileName(fileName);
553: }
554:
555: if (isSpecialFile) {
556: collabFileHandler
557: .setContentType(CollabFileHandler.TEXT_UNKNOWN);
558: }
559:
560: collabFileHandler.setContext(getContext());
561: manager.addFileHandler(collabFileHandler);
562: } else {
563: throw new CollabException(
564: "No CollabFileHandlerFactory matches for "
565: + "Content Type: " + contentType);
566: }
567: }
568:
569: return collabFileHandler;
570: }
571:
572: /**
573: * removeCollabFileHandler
574: *
575: * @param id
576: * @throws CollabException
577: */
578: public void removeFileHandler(String fileName)
579: throws CollabException {
580: CollabFileHandler fileHandler = manager
581: .getFileHandler(fileName);
582: fileHandler.setValid(false);
583:
584: //remove all regions if already exist
585: fileHandler.clear();
586: this .fileNames.remove(fileName);
587: manager.removeFileHandler(fileName);
588: }
589:
590: /**
591: * handleSendFile
592: *
593: * @param sfds
594: * @param owner
595: * @throws CollabException
596: */
597: public void handleSendFile(final SendFileData[] sfds,
598: final String messageOriginator) throws CollabException {
599: if ((sfds == null) || (sfds.length == 0)) {
600: return;
601: }
602:
603: SwingUtilities.invokeLater(new Runnable() {
604: public void run() {
605: try {
606: Debug.log(this , "SendFileHandler, in run len: "
607: + sfds.length); //NoI18n
608:
609: //create project node
610: final String primaryFileName = FileshareUtil
611: .getNormalizedPath(sfds[0].getFileData()
612: .getFileName());
613: String[] tokens = primaryFileName
614: .split(FILE_SEPERATOR);
615: String owner = tokens[0];
616: String projectName = tokens[1];
617: createProjectNode(projectName, owner);
618:
619: //process files
620: processSendFile(sfds, owner);
621:
622: //add node
623: TimerTask t = new TimerTask() {
624: public void run() {
625: try {
626: addNode(primaryFileName,
627: getFileHandlers()[0]
628: .getFileObject());
629: } catch (Throwable th) {
630: th.printStackTrace(Debug.out);
631: }
632: }
633: };
634:
635: long delay = FilesharingConstants.PERIOD * 2;
636:
637: //form (==2 files) need time double time before addnode call
638: if (sfds.length > 1) {
639: delay = FilesharingConstants.PERIOD * 5;
640: }
641:
642: getContext().getTimer().schedule(t, delay);
643: } catch (Throwable th) {
644: Debug.log(this , "SendFileHandler, " + //NoI18n
645: "update file failed "); //NoI18n
646: Debug.logDebugException("SendFileHandler, " + //NoI18n
647: "update file failed ", //NoI18n
648: th, true);
649: }
650: }
651: });
652: }
653:
654: private void createProjectNode(final String projectName,
655: final String owner) throws CollabException {
656: Debug.log(this , "SendFileHandler, SFH projectName: "
657: + projectName);
658:
659: try {
660: FileSystem fs = getContext().getCollabFilesystem();
661: fs.runAtomicAction(new FileSystem.AtomicAction() {
662: public void run() throws IOException {
663: FileObject folder = null;
664: Debug.log(this ,
665: "SendFileHandler, SFH:: projectName: "
666: + projectName);
667: projectNode = getContext().createProjectNode(owner,
668: projectName);
669: }
670: });
671: } catch (IOException iox) {
672: throw new CollabException(iox);
673: }
674: }
675:
676: private void processSendFile(SendFileData[] sendFileData,
677: final String owner) throws CollabException {
678: for (int i = 0; i < sendFileData.length; i++) {
679: String fullPath = FileshareUtil
680: .getNormalizedPath(sendFileData[i].getFileData()
681: .getFileName());
682: Debug.log(this , "SendFileHandler, in run: " + i); //NoI18n
683:
684: String contentType = sendFileData[i].getFileData()
685: .getContentType();
686: Debug.log(this , "SendFileHandler, contentType: " + //NoI18n
687: contentType);
688:
689: CollabFileHandler fh = createFileHandler(fullPath,
690: contentType);
691: addFileHandler(fh);
692:
693: if ((fh != null) && fh instanceof CollabFormFileHandler) {
694: setType(SharedFileGroup.FORM_TYPE);
695: }
696: }
697:
698: for (int i = 0; i < sendFileData.length; i++) {
699: String fullPath = FileshareUtil
700: .getNormalizedPath(sendFileData[i].getFileData()
701: .getFileName());
702: CollabFileHandler fh = manager.getFileHandler(fullPath);
703: fh.setCurrentState(
704: FilesharingContext.STATE_RECEIVEDSENDFILE,
705: FilesharingTimerTask.PERIOD * 3, true, true);
706:
707: if (getType() == SharedFileGroup.FORM_TYPE) {
708: fh.setRetrieveFileContentOnly(true);
709: fh.setSkipUpdateAlways(true);
710: }
711:
712: fh.handleSendFile(owner, sendFileData[i]);
713:
714: if (getType() == SharedFileGroup.FORM_TYPE) {
715: fh.setSkipUpdateAlways(false);
716: }
717: }
718: }
719:
720: private void addNode(final String primaryFileName,
721: final FileObject primaryFile) throws CollabException {
722: if (primaryFileName != null) {
723: try {
724: FileSystem fs = getContext().getCollabFilesystem();
725: fs.runAtomicAction(new FileSystem.AtomicAction() {
726: public void run() throws IOException {
727: FileObject folder = null;
728:
729: try {
730: DataObject d = DataObject.find(primaryFile);
731: FilesystemExplorerPanel panel = getContext()
732: .getFilesystemExplorer();
733:
734: if ((panel != null)
735: && (panel.getRootNode() != null)) {
736: panel.getRootNode().processPaste(
737: projectNode,
738: new DataObject[] { d }, null,
739: false);
740: }
741: } catch (DataObjectNotFoundException ddnf) {
742: ddnf.printStackTrace(Debug.out);
743: }
744:
745: //expand path
746: FilesystemExplorerPanel panel = getContext()
747: .getFilesystemExplorer();
748:
749: if (panel != null) {
750: String filePath = primaryFileName;
751: int index = primaryFileName
752: .lastIndexOf(FILE_SEPERATOR);
753:
754: if (index != -1) {
755: filePath = primaryFileName.substring(0,
756: index);
757: }
758:
759: panel.expandTreeNode(filePath);
760: }
761: }
762: });
763: } catch (IOException iox) {
764: throw new CollabException(iox);
765: }
766: }
767: }
768:
769: private FilesharingContext getContext() {
770: if (context == null) {
771: context = manager.getContext();
772: }
773:
774: return context;
775: }
776: }
|