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.eventhandler;
042:
043: import org.openide.awt.UndoRedo;
044: import org.openide.windows.TopComponent;
045:
046: import java.util.HashMap;
047: import java.util.TimerTask;
048: import java.util.Vector;
049: import java.util.List;
050:
051: import javax.swing.SwingUtilities;
052:
053: import org.netbeans.modules.collab.channel.filesharing.filehandler.CollabRegion;
054:
055: import com.sun.collablet.CollabException;
056: import org.netbeans.modules.collab.core.Debug;
057: import org.netbeans.modules.collab.channel.filesharing.FilesharingConstants;
058: import org.netbeans.modules.collab.channel.filesharing.FilesharingContext;
059: import org.netbeans.modules.collab.channel.filesharing.filehandler.CollabFileHandler;
060: import org.netbeans.modules.collab.channel.filesharing.filehandler.CollabFileHandlerSupport;
061: import org.netbeans.modules.collab.channel.filesharing.filehandler.CollabLineRegion;
062: import org.netbeans.modules.collab.channel.filesharing.filehandler.EditorLock;
063: import org.netbeans.modules.collab.channel.filesharing.filehandler.RegionInfo;
064: import org.netbeans.modules.collab.channel.filesharing.msgbean.CCollab;
065: import org.netbeans.modules.collab.channel.filesharing.msgbean.LockRegion;
066: import org.netbeans.modules.collab.channel.filesharing.msgbean.LockRegionData;
067: import org.netbeans.modules.collab.channel.filesharing.msgbean.U2pResponse;
068: import org.netbeans.modules.collab.channel.filesharing.msgbean.Use2phase;
069:
070: /**
071: *
072: * @author askhan
073: */
074: public class LockRegionManager {
075: private String lockID;
076: private FilesharingContext context;
077: private String userID;
078: private String filename;
079: private RegionInfo regionInfo;
080: private CCollab collabBean;
081: private int userCount;
082: private HashMap replies = new HashMap();
083: private EditorLock editorLock = null;
084: private CollabFileHandler fileHandler = null;
085: private TimerTask tt = null;
086: private long lockRequestTime;
087: private boolean isValid;
088: private boolean isUserStarted2Phase = false;
089:
090: /** Creates a new instance of LockRegionManagerFactory */
091: public LockRegionManager(String lockID, FilesharingContext context,
092: String userID, RegionInfo regionInfo) {
093: Debug.log("FilesharingContext", "LRM, constructed: lockID: "
094: + lockID); //NoI18n
095: this .lockID = lockID;
096: this .context = context;
097: this .userID = userID;
098: this .filename = regionInfo.getFileName();
099: this .regionInfo = regionInfo;
100: getFileHandler(); //init
101: setValid(true);
102:
103: // remove lrm after 5 sec, since the 2phase lock should be done between 200ms to 2200ms
104: TimerTask cleanupTask = new TimerTask() {
105: public void run() {
106: Debug.log("FilesharingContext", "LRM, final cleanup"); //NoI18n
107: cleanup();
108: }
109: };
110: getContext().schedule(cleanupTask, 4000);
111: }
112:
113: private CollabFileHandler getFileHandler() {
114: if (fileHandler == null) {
115: fileHandler = getFileHandler(filename, context);
116: }
117:
118: return fileHandler;
119: }
120:
121: private static CollabFileHandler getFileHandler(String fname,
122: FilesharingContext context) {
123: return context.getSharedFileGroupManager()
124: .getFileHandler(fname);
125: }
126:
127: public void start2PhaseLock(final CCollab collabBean, int userCount)
128: throws CollabException {
129: Debug.log("FilesharingContext",
130: "LRM, start2PhaseLock for user: " + userID
131: + " region: " + regionInfo.getID()
132: + " userCount: " + userCount); //NoI18n
133: this .collabBean = collabBean;
134: this .isUserStarted2Phase = true;
135: this .userCount = userCount;
136:
137: //set use2phase element to lock message
138: Use2phase use2phase = new Use2phase();
139: use2phase.setUse2phaseId(this .lockID);
140: collabBean.getChLockRegion().setUse2phase(use2phase);
141:
142: CollabFileHandler fh = getFileHandler();
143:
144: //if this is the fileowner then no need for 2phase lock, send the beginlock msg
145: if (getContext().isFileOwner(getContext().getLoginUser(),
146: fh.getName())) {
147: sendBeginLockMessage(collabBean);
148: return;
149: }
150:
151: final long delay = FilesharingConstants.PERIOD * 2;
152: tt = new TimerTask() {
153: public void run() {
154: try {
155: if (LockRegionManager.this .isValid()) {
156: Debug.log("FilesharingContext",
157: "LRM, timertask start"); //NoI18n
158: sendBeginLockMessage(collabBean);
159: }
160: } catch (Throwable th) {
161: th.printStackTrace(Debug.out);
162: }
163: }
164: };
165: getContext().getTimer().schedule(tt, delay);
166: lockRequestTime = System.currentTimeMillis();
167: sendLockRequest(lockID, collabBean);
168: }
169:
170: public void undoDocumentUpdate() {
171: Debug.log("FilesharingContext", "LRM, undoDocumentUpdate"); //NoI18n
172: final CollabFileHandler fh = getFileHandler();
173:
174: if (fh == null) {
175: return;
176: }
177:
178: SwingUtilities.invokeLater(new Runnable() {
179: public void run() {
180: try {
181: TopComponent tc = ((CollabFileHandlerSupport) fh)
182: .findTopComponent();
183:
184: if (tc != null) {
185: UndoRedo undoRedo = tc.getUndoRedo();
186:
187: if (undoRedo != null) {
188: ((CollabFileHandlerSupport) fh)
189: .setSkipUpdate(true);
190: undoRedo.undo();
191: ((CollabFileHandlerSupport) fh)
192: .setSkipUpdate(false);
193: }
194: }
195: } catch (Throwable th) {
196: Debug.log("FilesharingContext", "LRM, " + //NoI18n
197: "cannot Undo change "); //NoI18n
198: Debug.logDebugException("LRM, " + //NoI18n
199: "cannot Undo change", //NoI18n
200: th, true);
201: }
202: }
203: });
204: }
205:
206: public void sendLockRequest(String use2phaseID, CCollab collabBean)
207: throws CollabException {
208: Debug.log("FilesharingContext", "LRM, sendLockRequest: "
209: + use2phaseID);//NoI18n
210: Use2phase use2phase = collabBean.getChLockRegion()
211: .getUse2phase();
212: if (use2phase == null) {
213: use2phase = new Use2phase();
214: use2phase.setUse2phaseId(this .lockID);
215: collabBean.getChLockRegion().setUse2phase(use2phase);
216: }
217: use2phase.setRequest(true);
218: sendMessage(collabBean);
219: }
220:
221: public boolean processLockReply(String user, CCollab collabBean)
222: throws CollabException {
223: Debug.log("FilesharingContext", "LRM, processLockReply: "
224: + userID); //NoI18n
225:
226: boolean beginLock = false;
227: Use2phase use2phase = collabBean.getChLockRegion()
228: .getUse2phase();
229:
230: CollabFileHandler fh = getFileHandler();
231: if (fh == null)
232: return false;
233:
234: //process "lock-region/use2phase/request" message if this user is file owner
235: if (use2phase.isRequest()
236: && getContext().isFileOwner(
237: getContext().getLoginUser(), fh.getName())) {
238: Debug.log("FilesharingContext", "LRM, processing request");//NoI18n
239: U2pResponse u2pResponse = new U2pResponse();
240: ((CollabFileHandlerSupport) fh).lockFileForCreateRegion();
241: if (isContentionFound()) {
242: Debug
243: .log("FilesharingContext",
244: "LRM, contention found");//NoI18n
245: u2pResponse.setContentionFound(true);
246: } else {
247: Debug.log("FilesharingContext",
248: "LRM, contention not found");//NoI18n
249: u2pResponse.setContentionNotfound(true);
250: //temporarily asssign these lineregions, then unassign if the requester
251: //didn't beginlock in 3 seconds
252: Vector lineRegions = regionInfo.getLineRegion();
253: long unassignDelay = 3000;
254: assignBeforeLockRegion(lineRegions, unassignDelay);
255: }
256: ((CollabFileHandlerSupport) fh).unlockFileForCreateRegion();
257:
258: use2phase.setResponse(u2pResponse);
259:
260: //reset request
261: use2phase.setRequest(false);
262: sendMessage(collabBean);
263: beginLock = false;
264: } else if (use2phase.isBegin()) { //process normal handleLock if "lock-region/use2phase/begin" message
265: Debug.log("FilesharingContext", "LRM, processing begin");//NoI18n
266: beginLock = true;
267: cleanup();
268: } else if (use2phase.getResponse() != null
269: && isUserStarted2Phase) {
270: //process response only if this user started 2phase Locking
271: Debug.log("FilesharingContext", "LRM, process response");//NoI18n
272: U2pResponse response = use2phase.getResponse();
273:
274: if (response.isContentionFound()) { //release any lock and start over
275: Debug
276: .log("FilesharingContext",
277: "LRM, contention found");//NoI18n
278: //received response from file owner, so start again
279: beginLock = false;
280: undoDocumentUpdate();
281: unAssignRegion(regionInfo.getID());
282: ((CollabFileHandlerSupport) fh)
283: .unlockFileForCreateRegion();
284: cleanup();
285: } else if (response.isContentionNotfound()) {
286: Debug.log("FilesharingContext",
287: "LRM, contention not found");//NoI18n
288: //received response from file owner, so beginlock
289: beginLock = false;
290: sendBeginLockMessage(collabBean);
291: }
292: }
293: return beginLock;
294: }
295:
296: private void unAssignRegion(String regionName)
297: throws CollabException {
298: Debug.log("FilesharingContext", "LRM, unAssignRegion region: "
299: + regionName); //NoI18n
300: CollabFileHandler fh = getFileHandler();
301: CollabRegion r = ((CollabFileHandlerSupport) fh)
302: .getRegion(regionName);
303: if (r != null)
304: r.setValid(false);
305:
306: List lines = ((CollabFileHandlerSupport) fh)
307: .getLineRegions(regionName);
308: if (lines != null) {
309: for (int i = 0; i < lines.size(); i++) {
310: CollabLineRegion liner = (CollabLineRegion) lines
311: .get(i);
312: if (liner != null) {
313: Debug.log("FilesharingContext", "LRM, setAssigned "
314: + "false for: " + liner.getID()); //NoI18n
315: liner.setAssigned(null, false);
316: }
317: }
318: }
319: ((CollabFileHandlerSupport) fh)
320: .removeRegion(userID, regionName);
321: }
322:
323: private void assignBeforeLockRegion(final Vector lineRegions,
324: long unassignDelay) throws CollabException {
325: Debug.log("FilesharingContext", "LRM, assignBeforeLockRegion");//NoI18n
326: if (lineRegions != null && lineRegions.size() > 0) {
327: Debug.log("FilesharingContext", "LRM, lineRegions.size: "
328: + lineRegions.size());//NoI18n
329: for (int i = 0; i < lineRegions.size(); i++) {
330: CollabLineRegion liner = (CollabLineRegion) lineRegions
331: .get(i);
332: if (liner != null) {
333: Debug.log("FilesharingContext", "LRM, setAssigned "
334: + "true for: " + liner.getID()); //NoI18n
335: liner.setAssigned(null, true);
336: }
337: }
338: }
339:
340: TimerTask unassignTask = new TimerTask() {
341: public void run() {
342: CollabLineRegion beginLine = (CollabLineRegion) lineRegions
343: .firstElement();
344: CollabLineRegion endLine = (CollabLineRegion) lineRegions
345: .lastElement();
346: // If these lineregions are not assigned yet, then unassign them
347: if (beginLine != null && endLine != null
348: && beginLine.getAssignedRegion() == null
349: && endLine.getAssignedRegion() == null) {
350: for (int i = 0; i < lineRegions.size(); i++) {
351: CollabLineRegion liner = (CollabLineRegion) lineRegions
352: .get(i);
353: if (liner != null) {
354: if (liner.getAssignedRegion() == null) {
355: Debug.log("FilesharingContext",
356: "LRM, setAssigned "
357: + "false for: "
358: + liner.getID()); //NoI18n
359: liner.setAssigned(null, false);
360: }
361: }
362: }
363: }
364: }
365: };
366: getContext().schedule(unassignTask, unassignDelay);
367: }
368:
369: private void sendBeginLockMessage(CCollab collabBean)
370: throws CollabException {
371: Debug.log("FilesharingContext", "LRM, sendBeginLockMessage");//NoI18n
372: if (!isValid()) {
373: return;
374: }
375:
376: long lockBeginTime = System.currentTimeMillis();
377: long delayLockBegin = lockBeginTime - lockRequestTime;
378: Debug.log("FilesharingContext", "LRM, sendBeginLockMessage"
379: + " after waiting for: " + delayLockBegin
380: + " millis begin: " + lockBeginTime + " request: "
381: + lockRequestTime + "user: " + userID + " lockID: "
382: + lockID); //NoI18n
383:
384: Use2phase use2phase = collabBean.getChLockRegion()
385: .getUse2phase();
386: use2phase.setBegin(true);
387: use2phase.setRequest(false);
388: use2phase.setResponse(null);
389: sendMessage(collabBean);
390: ((CollabFileHandlerSupport) fileHandler)
391: .unlockFileForCreateRegion();
392:
393: cleanup();
394: }
395:
396: private void cleanup() {
397: Debug.log("FilesharingContext", "LRM, cleanup");
398: if (tt != null)
399: tt.cancel();
400: setValid(false);
401: CollabFileHandler fh = getFileHandler();
402: if (fh != null) {
403: ((CollabFileHandlerSupport) fh)
404: .removeLockRegionManager(this .lockID);
405: }
406: }
407:
408: public boolean isContentionFound() throws CollabException {
409: boolean retVal = false;
410: CollabFileHandler fh = getFileHandler();
411:
412: if (fh != null) {
413: int beginLineN = -1;
414: int endLineN = -1;
415: Vector lineRegions = regionInfo.getLineRegion();
416:
417: if ((lineRegions != null) && (lineRegions.size() > 0)) {
418: Debug.log("FilesharingContext",
419: "LRM, lineRegions.size: " + lineRegions.size());//NoI18n
420: CollabLineRegion beginLine = (CollabLineRegion) lineRegions
421: .firstElement();
422: CollabLineRegion endLine = (CollabLineRegion) lineRegions
423: .lastElement();
424:
425: try {
426: if (beginLine != null && endLine != null)
427: retVal = ((CollabFileHandlerSupport) fh)
428: .isRegionOverlap(beginLine, endLine);
429: } catch (Exception e) {
430: Debug
431: .logDebugException("LRM, exception: ", e,
432: true);//NoI18n
433: //allow lock originator to continue
434: retVal = false;
435: }
436: }
437: }
438:
439: return retVal;
440: }
441:
442: private FilesharingContext getContext() {
443: return context;
444: }
445:
446: private void sendMessage(CCollab collabBean) throws CollabException {
447: context.sendMessage(collabBean);
448: getContext().printAllData(
449: "\nIn LRM::after sendMessage event: \n"
450: + "sendMessageLockRegion/"
451: + LockRegionManager
452: .getLockMessageType(collabBean)); //NoI18n
453: }
454:
455: public static String getLockMessageType(CCollab collabBean) {
456: String type = "";
457: Use2phase use2phase = collabBean.getChLockRegion()
458: .getUse2phase();
459:
460: if (use2phase == null) {
461: return type;
462: }
463:
464: if (use2phase.isRequest()) {
465: type = "Request"; //NoI18n
466: } else if (use2phase.isBegin()) {
467: type = "Begin"; //NoI18n
468: } else if (use2phase.getResponse() != null) {
469: type = "Response"; //NoI18n
470:
471: U2pResponse response = use2phase.getResponse();
472:
473: if (response.isContentionFound()) {
474: type += "/ContentionFound"; //NoI18n
475: } else {
476: type += "/ContentionNotFound"; //NoI18n
477: }
478: }
479:
480: return type;
481: }
482:
483: public void setValid(boolean valid) {
484: this .isValid = valid;
485: }
486:
487: public boolean isValid() {
488: return isValid;
489: }
490: }
|