KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > impl > DefaultScriptSession


1 /*
2  * Copyright 2005 Joe Walker
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.directwebremoting.impl;
17
18 import java.io.IOException JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26 import java.util.SortedSet JavaDoc;
27 import java.util.TreeSet JavaDoc;
28
29 import org.directwebremoting.ScriptBuffer;
30 import org.directwebremoting.extend.MarshallException;
31 import org.directwebremoting.extend.RealScriptSession;
32 import org.directwebremoting.extend.ScriptConduit;
33 import org.directwebremoting.util.Logger;
34
35 /**
36  * An implementation of ScriptSession and RealScriptSession.
37  * <p>There are synchronization constraints on this class. See the field
38  * comments of the type: <code>GuardedBy("lock")</code>.
39  * <p>In addition you should note that {@link DefaultScriptSession} and
40  * {@link DefaultScriptSessionManager} make calls to each other and you should
41  * take care not to break any constraints in inheriting from these classes.
42  * @author Joe Walker [joe at getahead dot ltd dot uk]
43  */

44 public class DefaultScriptSession implements RealScriptSession
45 {
46     /**
47      * Simple constructor
48      * @param id The new unique identifier for this session
49      * @param manager The manager that created us
50      */

51     protected DefaultScriptSession(String JavaDoc id, DefaultScriptSessionManager manager)
52     {
53         this.id = id;
54         if (id == null)
55         {
56             throw new IllegalArgumentException JavaDoc("id can not be null");
57         }
58
59         this.manager = manager;
60         this.creationTime = System.currentTimeMillis();
61         this.lastAccessedTime = creationTime;
62     }
63
64     /* (non-Javadoc)
65      * @see org.directwebremoting.ScriptSession#getAttribute(java.lang.String)
66      */

67     public Object JavaDoc getAttribute(String JavaDoc name)
68     {
69         checkNotInvalidated();
70         synchronized (attributes)
71         {
72             return attributes.get(name);
73         }
74     }
75
76     /* (non-Javadoc)
77      * @see org.directwebremoting.ScriptSession#setAttribute(java.lang.String, java.lang.Object)
78      */

79     public void setAttribute(String JavaDoc name, Object JavaDoc value)
80     {
81         checkNotInvalidated();
82         synchronized (attributes)
83         {
84             attributes.put(name, value);
85         }
86     }
87
88     /* (non-Javadoc)
89      * @see org.directwebremoting.ScriptSession#removeAttribute(java.lang.String)
90      */

91     public void removeAttribute(String JavaDoc name)
92     {
93         checkNotInvalidated();
94         synchronized (attributes)
95         {
96             attributes.remove(name);
97         }
98     }
99
100     /* (non-Javadoc)
101      * @see org.directwebremoting.ScriptSession#getAttributeNames()
102      */

103     public Iterator JavaDoc getAttributeNames()
104     {
105         checkNotInvalidated();
106         synchronized (attributes)
107         {
108             Set JavaDoc keys = Collections.unmodifiableSet(attributes.keySet());
109             return keys.iterator();
110         }
111     }
112
113     /* (non-Javadoc)
114      * @see org.directwebremoting.ScriptSession#invalidate()
115      */

116     public void invalidate()
117     {
118         synchronized (invalidLock)
119         {
120             invalidated = true;
121             manager.invalidate(this);
122         }
123     }
124
125     /* (non-Javadoc)
126      * @see org.directwebremoting.ScriptSession#isInvalidated()
127      */

128     public boolean isInvalidated()
129     {
130         synchronized (invalidLock)
131         {
132             return invalidated;
133         }
134     }
135
136     /* (non-Javadoc)
137      * @see org.directwebremoting.ScriptSession#getId()
138      */

139     public String JavaDoc getId()
140     {
141         return id;
142     }
143
144     /* (non-Javadoc)
145      * @see org.directwebremoting.ScriptSession#getCreationTime()
146      */

147     public long getCreationTime()
148     {
149         checkNotInvalidated();
150         return creationTime;
151     }
152
153     /* (non-Javadoc)
154      * @see org.directwebremoting.ScriptSession#getLastAccessedTime()
155      */

156     public long getLastAccessedTime()
157     {
158         synchronized (invalidLock)
159         {
160             // For many accesses here we check to see if we should invalidate
161
// ourselves, but getLastAccessedTime() is used as part of the process
162
// that DefaultScriptSessionManager goes through in order to check
163
// everything for validity. So if we do this check here then DSSM will
164
// give a ConcurrentModificationException if anything does timeout
165
// checkNotInvalidated();
166
return lastAccessedTime;
167         }
168     }
169
170     /* (non-Javadoc)
171      * @see org.directwebremoting.ScriptSession#addScript(java.lang.String)
172      */

173     public void addScript(ScriptBuffer script)
174     {
175         checkNotInvalidated();
176
177         if (script == null)
178         {
179             throw new NullPointerException JavaDoc("null script");
180         }
181
182         // log.debug("addScript() to " + this);
183

184         // First we try to add the script to an existing conduit
185
synchronized (scriptLock)
186         {
187             if (conduits.size() == 0)
188             {
189                 // There are no conduits, just store it until there are
190
scripts.add(script);
191                 // log.debug("- No conduits. Adding script to waiting list");
192
}
193             else
194             {
195                 // Try all the conduits, starting with the first
196
boolean written = false;
197                 for (Iterator JavaDoc it = conduits.iterator(); !written && it.hasNext();)
198                 {
199                     ScriptConduit conduit = (ScriptConduit) it.next();
200                     try
201                     {
202                         written = conduit.addScript(script);
203                         // log.debug("- Adding script to conduit (written=" + written + "): " + conduit);
204
}
205                     catch (Exception JavaDoc ex)
206                     {
207                         it.remove();
208                         log.debug("Failed to write to ScriptConduit, removing from list: " + conduit);
209                     }
210                 }
211
212                 if (!written)
213                 {
214                     scripts.add(script);
215                     // log.debug("- No conduits passed it on. Adding script to waiting list");
216
}
217             }
218         }
219     }
220
221     /* (non-Javadoc)
222      * @see org.directwebremoting.extend.RealScriptSession#addScriptConduit(org.directwebremoting.extend.ScriptConduit)
223      */

224     public void addScriptConduit(ScriptConduit conduit) throws IOException JavaDoc
225     {
226         checkNotInvalidated();
227
228         synchronized (scriptLock)
229         {
230             writeScripts(conduit);
231             conduits.add(conduit);
232
233             // log.debug("Adding Conduit: conduit=" + conduit + " scriptsession=" + this);
234
}
235     }
236
237     /* (non-Javadoc)
238      * @see org.directwebremoting.extend.RealScriptSession#writeScripts(org.directwebremoting.extend.ScriptConduit)
239      */

240     public void writeScripts(ScriptConduit conduit) throws IOException JavaDoc
241     {
242         checkNotInvalidated();
243
244         synchronized (scriptLock)
245         {
246             for (Iterator JavaDoc it = scripts.iterator(); it.hasNext();)
247             {
248                 ScriptBuffer script = (ScriptBuffer) it.next();
249
250                 try
251                 {
252                     if (conduit.addScript(script))
253                     {
254                         // log.debug("Adding stored script to conduit: " + conduit);
255
it.remove();
256                     }
257                     else
258                     {
259                         // If we didn't write this one, don't bother with any more
260
break;
261                     }
262                 }
263                 catch (MarshallException ex)
264                 {
265                     log.warn("Failed to convert data. Dropping Javascript: " + script, ex);
266                 }
267             }
268         }
269     }
270
271     /* (non-Javadoc)
272      * @see org.directwebremoting.extend.RealScriptSession#removeScriptConduit(org.directwebremoting.extend.ScriptConduit)
273      */

274     public void removeScriptConduit(ScriptConduit conduit)
275     {
276         checkNotInvalidated();
277
278         synchronized (scriptLock)
279         {
280             boolean removed = conduits.remove(conduit);
281             if (!removed)
282             {
283                 log.debug("Removing unattached ScriptConduit: " + conduit);
284                 debug();
285             }
286         }
287
288         // log.debug("Removing Conduit: conduit=" + conduit + " scriptsession=" + this);
289
}
290
291     /* (non-Javadoc)
292      * @see org.directwebremoting.extend.RealScriptSession#getScriptLock()
293      */

294     public Object JavaDoc getScriptLock()
295     {
296         return scriptLock;
297     }
298
299     /* (non-Javadoc)
300      * @see org.directwebremoting.extend.RealScriptSession#hasWaitingScripts()
301      */

302     public boolean hasWaitingScripts()
303     {
304         synchronized (scriptLock)
305         {
306             return !scripts.isEmpty();
307         }
308     }
309
310     /**
311      * Called whenever a browser accesses this data using DWR
312      */

313     protected void updateLastAccessedTime()
314     {
315         synchronized (invalidLock)
316         {
317             lastAccessedTime = System.currentTimeMillis();
318         }
319     }
320
321     /**
322      * Check that we are still valid and throw an IllegalStateException if not.
323      * At the same time set the lastAccessedTime flag.
324      * @throws IllegalStateException If this object has become invalid
325      */

326     protected void checkNotInvalidated()
327     {
328         synchronized (invalidLock)
329         {
330             long now = System.currentTimeMillis();
331             long age = now - lastAccessedTime;
332             if (age > manager.getScriptSessionTimeout())
333             {
334                 invalidate();
335             }
336
337             if (invalidated)
338             {
339                 log.debug("ScriptSession has been invalidated.");
340             }
341         }
342     }
343
344     /**
345      * Some debug output
346      */

347     private void debug()
348     {
349         if (log.isDebugEnabled())
350         {
351             log.debug("Known ScriptConduits:");
352             for (Iterator JavaDoc it = conduits.iterator(); it.hasNext();)
353             {
354                 ScriptConduit c = (ScriptConduit) it.next();
355                 log.debug("- " + c);
356             }
357         }
358     }
359
360     /* (non-Javadoc)
361      * @see java.lang.Object#hashCode()
362      */

363     public int hashCode()
364     {
365         return 572 + id.hashCode();
366     }
367
368     /* (non-Javadoc)
369      * @see java.lang.Object#equals(java.lang.Object)
370      */

371     public boolean equals(Object JavaDoc obj)
372     {
373         if (obj == null)
374         {
375             return false;
376         }
377
378         if (obj == this)
379         {
380             return true;
381         }
382
383         if (!this.getClass().equals(obj.getClass()))
384         {
385             return false;
386         }
387
388         DefaultScriptSession that = (DefaultScriptSession) obj;
389
390         if (!this.id.equals(that.id))
391         {
392             return false;
393         }
394
395         return true;
396     }
397
398     /* (non-Javadoc)
399      * @see java.lang.Object#toString()
400      */

401     public String JavaDoc toString()
402     {
403         return "DefaultScriptSession[id=" + id + "]";
404     }
405
406     /**
407      * The server side attributes for this page.
408      * <p>GuardedBy("attributes")
409      */

410     protected final Map JavaDoc attributes = Collections.synchronizedMap(new HashMap JavaDoc());
411
412     /**
413      * When the the web page that we represent last contact us using DWR?
414      * <p>GuardedBy("invalidLock")
415      */

416     protected long lastAccessedTime = 0L;
417
418     /**
419      * Have we been made invalid?
420      * <p>GuardedBy("invalidLock")
421      */

422     protected boolean invalidated = false;
423
424     /**
425      * The object that we use to synchronize against when we want to work with
426      * the invalidation state of this object
427      */

428     private final Object JavaDoc invalidLock = new Object JavaDoc();
429
430     /**
431      * The script conduits that we can use to transfer data to the browser.
432      * <p>GuardedBy("scriptLock")
433      */

434     protected final SortedSet JavaDoc conduits = new TreeSet JavaDoc();
435
436     /**
437      * The list of waiting scripts.
438      * <p>GuardedBy("scriptLock")
439      */

440     protected final List JavaDoc scripts = new ArrayList JavaDoc();
441
442     /**
443      * The object that we use to synchronize against when we want to alter
444      * the path of scripts (to conduits or the scripts list)
445      */

446     private final Object JavaDoc scriptLock = new Object JavaDoc();
447
448     /**
449      * What is our page session id?
450      * <p>This should not need careful synchronization since it is unchanging
451      */

452     protected final String JavaDoc id;
453
454     /**
455      * When we we created?
456      * <p>This should not need careful synchronization since it is unchanging
457      */

458     protected final long creationTime;
459
460     /**
461      * The session manager that collects sessions together
462      * <p>This should not need careful synchronization since it is unchanging
463      */

464     protected final DefaultScriptSessionManager manager;
465
466     /**
467      * The log stream
468      */

469     private static final Logger log = Logger.getLogger(DefaultScriptSession.class);
470 }
471
Popular Tags