001: /*
002: License $Id: JoRemoteSessionContext.java,v 1.6 2005/03/15 20:09:44 hendriks73 Exp $
003:
004: Copyright (c) 2001-2005 tagtraum industries.
005:
006: LGPL
007: ====
008:
009: jo! is free software; you can redistribute it and/or
010: modify it under the terms of the GNU Lesser General Public
011: License as published by the Free Software Foundation; either
012: version 2.1 of the License, or (at your option) any later version.
013:
014: jo! is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018:
019: You should have received a copy of the GNU Lesser General Public
020: License along with this library; if not, write to the Free Software
021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022:
023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
024:
025:
026: Sun license
027: ===========
028:
029: This release contains software by Sun Microsystems. Therefore
030: the following conditions have to be met, too. They apply to the
031: files
032:
033: - lib/mail.jar
034: - lib/activation.jar
035: - lib/jsse.jar
036: - lib/jcert.jar
037: - lib/jaxp.jar
038: - lib/crimson.jar
039: - lib/servlet.jar
040: - lib/jnet.jar
041: - lib/jaas.jar
042: - lib/jaasmod.jar
043:
044: contained in this release.
045:
046: a. Licensee may not modify the Java Platform
047: Interface (JPI, identified as classes contained within the javax
048: package or any subpackages of the javax package), by creating additional
049: classes within the JPI or otherwise causing the addition to or modification
050: of the classes in the JPI. In the event that Licensee creates any
051: Java-related API and distribute such API to others for applet or
052: application development, you must promptly publish broadly, an accurate
053: specification for such API for free use by all developers of Java-based
054: software.
055:
056: b. Software is confidential copyrighted information of Sun and
057: title to all copies is retained by Sun and/or its licensors. Licensee
058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
059: reverse engineer Software. Software may not be leased, assigned, or
060: sublicensed, in whole or in part. Software is not designed or intended
061: for use in on-line control of aircraft, air traffic, aircraft navigation
062: or aircraft communications; or in the design, construction, operation or
063: maintenance of any nuclear facility. Licensee warrants that it will not
064: use or redistribute the Software for such purposes.
065:
066: c. Software is provided "AS IS," without a warranty
067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
070:
071: d. This License is effective until terminated. Licensee may
072: terminate this License at any time by destroying all copies of Software.
073: This License will terminate immediately without notice from Sun if Licensee
074: fails to comply with any provision of this License. Upon such termination,
075: Licensee must destroy all copies of Software.
076:
077: e. Software, including technical data, is subject to U.S.
078: export control laws, including the U.S. Export Administration Act and its
079: associated regulations, and may be subject to export or import regulations
080: in other countries. Licensee agrees to comply strictly with all such
081: regulations and acknowledges that it has the responsibility to obtain
082: licenses to export, re-export, or import Software. Software may not be
083: downloaded, or otherwise exported or re-exported (i) into, or to a national
084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
087: Commerce Department's Table of Denial Orders.
088:
089:
090: Feedback
091: ========
092:
093: We encourage your feedback and suggestions and want to use your feedback to
094: improve the Software. Send all such feedback to:
095: <feedback@tagtraum.com>
096:
097: For more information on tagtraum industries and jo!
098: please see <http://www.tagtraum.com/>.
099:
100:
101: */
102: package com.tagtraum.jobalancer;
103:
104: import com.tagtraum.framework.log.C_Log;
105: import com.tagtraum.framework.log.Log;
106: import com.tagtraum.framework.server.I_BasicService;
107: import com.tagtraum.jo.I_JoSession;
108:
109: import java.rmi.RemoteException;
110: import java.rmi.registry.LocateRegistry;
111: import java.rmi.registry.Registry;
112: import java.rmi.server.UnicastRemoteObject;
113: import java.util.Enumeration;
114: import java.util.HashSet;
115: import java.util.Hashtable;
116:
117: /**
118: *
119: *
120: * @author Hendrik Schreiber
121: * @version 1.1beta1 $Id: JoRemoteSessionContext.java,v 1.6 2005/03/15 20:09:44 hendriks73 Exp $
122: */
123: public class JoRemoteSessionContext extends UnicastRemoteObject
124: implements I_BasicService, I_JoRemoteSessionContext, Runnable,
125: C_JoBalancer {
126:
127: /**
128: * Source-Version
129: */
130: public static String vcid = "$Id: JoRemoteSessionContext.java,v 1.6 2005/03/15 20:09:44 hendriks73 Exp $";
131:
132: /**
133: * Datenstruktur, in der die Sessions gehalten werden
134: */
135: // hier k�nnte eine Persistence-Engine untergebracht werden
136: protected Hashtable mySessions;
137:
138: /**
139: * InvalidationTime in s
140: */
141: protected int myDefaultMaxInactiveInterval;
142:
143: /**
144: * InvalidationIntervall in ms
145: */
146: protected long myInvalidationIntervall;
147:
148: /**
149: * Flag, ob der Kontext läuft
150: */
151: protected boolean running;
152:
153: /**
154: * IDExtension.
155: */
156: protected int myIDExtension;
157:
158: /**
159: * Number of registered clients.
160: */
161: protected HashSet myRegisteredClients;
162:
163: /**
164: * Name of this service.
165: */
166: protected String myName;
167:
168: /**
169: * Attributes of this service.
170: */
171: protected Hashtable myAttributes;
172:
173: /**
174: * Running since
175: */
176: protected long myRunningSince;
177:
178: /**
179: *
180: */
181: protected int gcEveryXChecks;
182:
183: /**
184: *
185: */
186: protected int checkCount;
187:
188: /**
189: * Watchdog thread.
190: */
191: protected Thread myThread;
192:
193: /**
194: * Constructor.
195: *
196: *
197: * @see
198: */
199: public JoRemoteSessionContext() throws RemoteException {
200: super ();
201:
202: running = false;
203: myRunningSince = 0;
204: mySessions = new Hashtable();
205: myThread = new Thread(this );
206: myAttributes = new Hashtable();
207: myInvalidationIntervall = C_DefaultInvalidationIntervall;
208: myRegisteredClients = new HashSet();
209: }
210:
211: /**
212: * Initialisiert den Kontext.
213: */
214: public void start()
215: throws com.tagtraum.framework.server.ServerException {
216: mySessions.clear();
217:
218: myIDExtension = 99;
219: // this looks nasty (rik)
220: myDefaultMaxInactiveInterval = 30 * 60; // 30 min
221: // loadSerializableSessions(); // disabled for now
222: gcEveryXChecks = (int) ((1000L * 60L * 1L) / myInvalidationIntervall); // every minute
223: running = true;
224: myRunningSince = System.currentTimeMillis();
225:
226: myThread.start();
227:
228: if (Log.getLog(getName()).isLog(C_Log.MODULE)) {
229: Log.getLog(getName()).log(
230: "Service '" + getName() + "' started.",
231: C_Log.MODULE);
232: }
233: }
234:
235: /**
236: * Überprüft regelmäßig alle Sessions auf ihre Gültigkeit.
237: */
238: public void run() {
239: try {
240: synchronized (this ) {
241: while (running) {
242: wait(myInvalidationIntervall);
243:
244: try {
245: checkSessions();
246: } catch (Throwable t) {
247: if (Log.getLog(getName()).isLog(C_Log.ERROR)) {
248: Log.getLog(getName()).log(t, C_Log.ERROR);
249: }
250: }
251: }
252: }
253: } catch (InterruptedException ignore) {
254: }
255:
256: running = false;
257: }
258:
259: /**
260: * Stops the context.
261: *
262: * @see #invalidateAllSessions()
263: */
264: public synchronized void stop()
265: throws com.tagtraum.framework.server.ServerException {
266: if (myRegisteredClients.size() > 0
267: && Log.getLog(getName()).isLog(C_Log.ERROR)) {
268: Log
269: .getLog(getName())
270: .log(
271: "WARNING: There are still instances of jo connected registered with this Service: "
272: + myRegisteredClients, C_Log.ERROR);
273: // storeSerializableSessions(); // disabled for now
274: }
275:
276: try {
277: invalidateAllSessions();
278: } catch (RemoteException re) {
279: throw new com.tagtraum.framework.server.ServerException(re);
280: }
281:
282: running = false;
283:
284: notify();
285:
286: myRunningSince = 0;
287:
288: if (Log.getLog(getName()).isLog(C_Log.MODULE)) {
289: Log.getLog(getName()).log(
290: "Service '" + getName() + "' stopped.",
291: C_Log.MODULE);
292: }
293: }
294:
295: /**
296: * Restarts this <code>Service</code>.
297: *
298: * @exception com.tagtraum.framework.server.ServerException if it is not possible to
299: * either start or stop this <code>Service</code>
300: */
301: public synchronized void restart()
302: throws com.tagtraum.framework.server.ServerException {
303: stop();
304: start();
305: }
306:
307: /**
308: * Indicates whether this <code>Service</code> is alive or not.
309: *
310: * @return <code>true</code> or <code>false</code>
311: */
312: public synchronized boolean isAlive() {
313: return running;
314: }
315:
316: /**
317: * Returns the time when the service was started
318: *
319: * @return the time when the service was started
320: */
321: public long runningSince() {
322: return myRunningSince;
323: }
324:
325: /**
326: * Returns an attribute.
327: *
328: * @return the attribute or <code>null</code>, if it doesn't exist.
329: * @param key the attribute's key
330: */
331: public Object getAttribute(String key) {
332: return myAttributes.get(key);
333: }
334:
335: /**
336: * Sets an attribute.
337: *
338: * @param key key of this attribute
339: * @param value value of this attribute
340: */
341: public void setAttribute(String key, Object value) {
342: myAttributes.put(key, value);
343: }
344:
345: /**
346: * Enumeration of all attribute keys.
347: *
348: * @return an Enumeration of all attribute keys
349: */
350: public Enumeration getAttributeNames() {
351: return myAttributes.keys();
352: }
353:
354: /**
355: * Returns the name of this <code>Service</code>.
356: *
357: * @return the name of this <code>Service</code>
358: */
359: public String getName() {
360: return myName;
361: }
362:
363: /**
364: * Sets the name of this <code>Service</code>.
365: *
366: * @param name name of this <code>Service</code>
367: */
368: public void setName(String name) {
369: if (name == null) {
370: throw new NullPointerException(
371: "Name of service can't be null.");
372: }
373:
374: myName = name;
375: }
376:
377: /*
378: *
379: * public void storeSerializableSessions() {
380: * ObjectOutputStream out = null;
381: * try {
382: * out = new ObjectOutputStream(new FileOutputStream(myPeer.getName() + "_sessions.serialized"));
383: * out.writeObject(mySessions);
384: * }
385: * catch (IOException io) {
386: * Log.getLog(host.getName()).log(io);
387: * }
388: * finally {
389: * try {
390: * if (out != null) out.close();
391: * }
392: * catch (IOException ioe) {
393: * Log.getLog(host.getName()).log(ioe);
394: * }
395: * }
396: * }
397: *
398: * public void loadSerializableSessions() {
399: * ObjectInputStream in = null;
400: * try {
401: * in = new ObjectInputStream(new FileInputStream(myPeer.getName() + "_sessions.serialized"));
402: * mySessions = (Hashtable)in.readObject();
403: * Enumeration e = mySessions.elements();
404: * while (e.hasMoreElements()) {
405: * I_JoSession theSession = (I_JoSession)e.nextElement();
406: * theSession.setSessionContext(this);
407: * }
408: * }
409: * catch (FileNotFoundException fnfe) {
410: * Log.getLog(host.getName()).log("No serialized sessions found for ServletContext " + myPeer.getName());
411: * }
412: * catch (Exception e) {
413: * Log.getLog(host.getName()).log(e);
414: * }
415: * finally {
416: * try {
417: * if (in != null) in.close();
418: * }
419: * catch (IOException ioe) {
420: * Log.getLog(host.getName()).log(ioe);
421: * }
422: * }
423: * }
424: *
425: */
426:
427: /**
428: * Checks all sessions.
429: */
430: protected void checkSessions() throws RemoteException {
431: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
432: Log.getLog(getName()).log(
433: "Checking sessions: " + mySessions.size(),
434: C_Log.METHOD);
435:
436: long free = Runtime.getRuntime().freeMemory();
437: long total = Runtime.getRuntime().totalMemory();
438: long used = total - free;
439: int ratio = (int) ((free * 100) / total);
440:
441: Log.getLog(getName()).log(
442: "Used memory: " + used + ", free memory: " + free
443: + ", total memory: " + total + ", ratio: "
444: + ratio, C_Log.METHOD);
445: }
446:
447: if (checkCount >= gcEveryXChecks) {
448: System.gc();
449:
450: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
451: Log.getLog(getName()).log("Ran gc");
452: }
453:
454: checkCount = 0;
455:
456: checkSessions();
457:
458: return;
459: }
460:
461: checkCount++;
462:
463: long now = System.currentTimeMillis();
464: Enumeration e = mySessions.elements();
465: I_JoRemoteSession aSession;
466:
467: while (e.hasMoreElements()) {
468: aSession = (I_JoRemoteSession) e.nextElement();
469:
470: long max = aSession.getLastAccessedTime();
471:
472: if (aSession.getLastAccessedTime() < aSession
473: .getCreationTime()) {
474: max = aSession.getCreationTime();
475: }
476:
477: if ((now - max) > aSession.getMaxInactiveInterval() * 1000) {
478: aSession.invalidate();
479: }
480: }
481: }
482:
483: /**
484: * Registers a wrapper at a RemoteSessionContext.
485: */
486: public void register(String joName) throws RemoteException {
487: if (!myRegisteredClients.add(joName)
488: && Log.getLog(getName()).isLog(C_Log.ERROR)) {
489: Log.getLog(getName()).log(
490: "WARNING: The server you are trying to register was already registered: "
491: + joName);
492: }
493:
494: if (Log.getLog(getName()).isLog(C_Log.MODULE)) {
495: Log.getLog(getName()).log("Registered: " + joName);
496: }
497: }
498:
499: /**
500: * Returns a unique new sessionid.
501: *
502: * @return new session ID
503: */
504: public String getNewId() throws RemoteException {
505: if (myIDExtension < 999) {
506: myIDExtension++;
507: } else {
508: myIDExtension = 99;
509: }
510:
511: String fullNewID = Long
512: .toString(System.currentTimeMillis(), 36)
513: + Integer.toString(myIDExtension, 36);
514:
515: return fullNewID.substring(2);
516: }
517:
518: /**
519: * Unregisters this client from the RemoteSessionContext.
520: */
521: public void unregister(String joName) throws RemoteException {
522: if (Log.getLog(getName()).isLog(C_Log.MODULE)) {
523: Log.getLog(getName()).log("Unregistered: " + joName);
524: }
525:
526: myRegisteredClients.remove(joName);
527: }
528:
529: /**
530: * Returns the session with the specified id.
531: *
532: * @param sessionID the id
533: * @return the sesseion or <code>null</code>
534: */
535: public I_JoRemoteSession getSession(String sessionId)
536: throws RemoteException {
537: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
538: Log.getLog(getName()).log(
539: "Call to getSession(" + sessionId + ").",
540: C_Log.METHOD);
541: }
542:
543: I_JoRemoteSession aSession = (I_JoRemoteSession) mySessions
544: .get(sessionId);
545:
546: if (aSession != null) {
547: aSession.markAccessed();
548: }
549:
550: return aSession;
551: }
552:
553: /**
554: * Creates a new session.
555: *
556: * @return Session or <code>null</code>
557: */
558: public I_JoRemoteSession newSession() throws RemoteException {
559: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
560: Log.getLog(getName()).log("Generated new session.",
561: C_Log.METHOD);
562: }
563:
564: I_JoRemoteSession theSession = new JoRemoteSession(); // should make this a factory (rik)
565:
566: theSession.setSessionContext(this );
567:
568: return theSession;
569: }
570:
571: /**
572: * Adds a session to the RemoteSessionContext
573: *
574: * @param aSession a session
575: */
576: public void addSession(I_JoRemoteSession aSession)
577: throws RemoteException {
578: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
579: Log.getLog(getName()).log(
580: "Added a session. Now " + mySessions.size()
581: + " are active.", C_Log.METHOD);
582: }
583:
584: mySessions.put(aSession.getId(), aSession);
585: }
586:
587: /**
588: * Removes a session.
589: *
590: * @param anID a sessionID
591: */
592: public void removeSession(String anID) throws RemoteException {
593: mySessions.remove(anID);
594:
595: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
596: Log.getLog(getName()).log(
597: "Removed a session. Now " + mySessions.size()
598: + " are active.", C_Log.METHOD);
599: }
600: }
601:
602: /**
603: * Invalidates all sessions.
604: */
605: public void invalidateAllSessions() throws RemoteException {
606: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
607: Log.getLog(getName()).log("Invalidating all session.",
608: C_Log.METHOD);
609: }
610:
611: Enumeration e = mySessions.elements();
612:
613: while (e.hasMoreElements()) {
614: ((I_JoSession) e.nextElement()).invalidate();
615: }
616: }
617:
618: /**
619: * Returns the MaxInactiveInterval all sessions are initialized with.
620: *
621: * @return MaxInactiveInterval in seconds
622: */
623: public int getDefaultMaxInactiveInterval() throws RemoteException {
624: return myDefaultMaxInactiveInterval;
625: }
626:
627: /**
628: * Sets the MaxInactiveInterval, all sessions
629: * are initialized with
630: *
631: * @param interval MaxInactiveInterval in seconds
632: */
633: public void setDefaultMaxInactiveInterval(int interval)
634: throws RemoteException {
635: myDefaultMaxInactiveInterval = interval;
636: }
637:
638: /**
639: * Method.
640: *
641: *
642: * @param args
643: *
644: * @throws Exception
645: *
646: * @see
647: */
648: public static void main(String args[]) throws Exception {
649: Class.forName(C_Default_SessionContextClassname + "_Stub");
650:
651: Registry theRegistry;
652:
653: // create Registry if necessary
654: try {
655: theRegistry = LocateRegistry.getRegistry(
656: C_Default_RegistryHost, C_Default_RegistryPort);
657:
658: theRegistry.list();
659: } catch (Exception e) {
660: theRegistry = null;
661: }
662:
663: if (theRegistry == null) {
664: theRegistry = LocateRegistry
665: .createRegistry(C_Default_RegistryPort);
666: }
667:
668: JoRemoteSessionContext theContext = (JoRemoteSessionContext) Class
669: .forName(C_Default_SessionContextClassname)
670: .newInstance();
671:
672: theContext.setName(C_Default_RegistryEntryName);
673: theContext.start();
674: theRegistry.rebind(C_Default_RegistryEntryName, theContext);
675: }
676:
677: }
|