1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package de.bea.domingo.proxy;
24
25 import java.applet.Applet;
26 import java.lang.ref.WeakReference;
27 import java.util.Collection;
28 import java.util.ConcurrentModificationException;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.Map;
32
33 import lotus.domino.NotesError;
34 import lotus.domino.NotesException;
35 import lotus.domino.NotesFactory;
36 import lotus.domino.NotesThread;
37 import lotus.domino.Session;
38 import de.bea.domingo.DNotesFactory;
39 import de.bea.domingo.DNotesMonitor;
40 import de.bea.domingo.DNotesRuntimeException;
41 import de.bea.domingo.DSession;
42 import de.bea.domingo.cache.Cache;
43 import de.bea.domingo.cache.WeakCache;
44 import de.bea.domingo.exception.DominoException;
45 import de.bea.domingo.i18n.ResourceManager;
46 import de.bea.domingo.i18n.Resources;
47 import de.bea.domingo.monitor.MonitorEnabled;
48 import de.bea.domingo.monitor.NullMonitor;
49
50 /***
51 * Factory for sessions to Notes/Domino.
52 *
53 * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
54 */
55 public final class NotesProxyFactory extends DNotesFactory implements MonitorEnabled {
56
57
58
59
60
61 /*** Retry count while waiting for disposal. */
62 public static final int MAX_DISPOSE_TRIES = 10;
63
64 /*** Time to wait for garbage collector [milliseconds]. */
65 public static final int TIME_WAIT_FOR_GC = 100;
66
67 /*** Threshold size for weak cache. */
68 public static final int DEFAULT_CACHE_THRESHOLD = 2000;
69
70 /*** Key for map of default IIOP session. */
71 public static final String DEFAULT_IIOP_SESSION_KEY = "defaultIIOPSession";
72
73 /*** Internationalized resources. */
74 private static final Resources RESOURCES = ResourceManager.getPackageResources(NotesProxyFactory.class);
75
76
77
78
79
80 /*** Associated internal session (local call only). */
81 private DSession fInternalSession;
82
83 /*** Map of all IIOP session (one session for each host and username). */
84 private Map fIiopSessions = new HashMap();
85
86 /*** Base Monitor instance. */
87 private DNotesMonitor fMonitor = null;
88
89 /*** Reference to recycle strategy implementation. */
90 private NotesRecycler fRecycler = null;
91
92 /*** Central weak cache for all Notes Proxy classes. */
93 private Cache fBaseCache = new WeakCache();
94
95 /*** Threshold size for weak cache. */
96 private int fCacheThreshold = DEFAULT_CACHE_THRESHOLD;
97
98
99
100
101
102 /***
103 * Default constructor.
104 *
105 * <p>Must be public to allow abstract factory (the base class) to create
106 * an instance of this class.</p>
107 */
108 public NotesProxyFactory() {
109 setMonitor(NullMonitor.getInstance());
110 fCacheThreshold = DNotesFactory.getIntProperty("de.bea.domingo.cache.threshold", DEFAULT_CACHE_THRESHOLD);
111 }
112
113 /***
114 * Package-private constructor to create a factory from within the Lotus Notes VM with
115 * restricted security.
116 *
117 * @param threshold Threshold size for weak cache
118 */
119 public NotesProxyFactory(final int threshold) {
120 setMonitor(NullMonitor.getInstance());
121 if (threshold > 0) {
122 fCacheThreshold = threshold;
123 } else {
124 fCacheThreshold = DEFAULT_CACHE_THRESHOLD;
125 }
126 }
127
128 /***
129 * Shutdown thread of Domingo, disposes all resources.
130 *
131 * @author <a href="mailto:kriede@users.sourceforge.net">Kurt Riede</a>
132 */
133 public final class DNotesShutdownThread extends Thread {
134
135 /***
136 * Tries to disposes all related resources.
137 *
138 * @see java.lang.Runnable#run()
139 */
140 public void run() {
141 try {
142 getMonitor().debug(RESOURCES.getString("shutdownhook.starting"));
143 getMonitor().debug("baseCache.size = " + getBaseCache().size());
144 DNotesFactory.dispose();
145 getMonitor().debug(RESOURCES.getString("shutdownhook.finished"));
146 } catch (DNotesRuntimeException e) {
147 getMonitor().warn(e.getLocalizedMessage(), e);
148 }
149 super.run();
150 }
151 }
152
153 /***
154 * Chooses a recycling strategy based on the Notes Client Release.
155 *
156 * Currently we think that even with R6 and later, the
157 * {@link RecycleStrategy} is the best choice and we don't use the
158 * {@link NoRecycleStrategy}. Especially the indeterministic caching of
159 * documents prohibits the {@link NoRecycleStrategy}.
160 *
161 * @param session the Notes Session
162 */
163 private void setRecycler(final Session session) {
164 fRecycler = new RecycleStrategy(getMonitor());
165 }
166
167 /***
168 * Returns the central weak cache of all notes objects.
169 *
170 * @return central weak cache of all notes objects
171 */
172 public Cache getBaseCache() {
173 return fBaseCache;
174 }
175
176 /***
177 * @see de.bea.domingo.DNotesFactory#gc()
178 * @deprecated only use this method for testing
179 */
180 public void gc() {
181 preprocessMethod();
182 }
183
184 /***
185 * <p>In this single threaded implementation, first the own reference
186 * to the session is nulled and then we wait for the weak cache to
187 * be finalized.
188 *
189 * @param force indicates if disposal should happen even if still any
190 * strong or soft reference exists. if <code>false</code>,
191 * only weak references must remain.
192 *
193 * @see de.bea.domingo.DNotesFactory#dispose()
194 * @see de.bea.domingo.DNotesFactory#dispose(boolean)
195 * @see java.lang.ref.WeakReference
196 * @deprecated use {@link #disposeInternal(boolean)} instead
197 */
198 public void disposeInternal(final boolean force) {
199 disposeInstance(force);
200 }
201
202 /***
203 * <p>In this single threaded implementation, first the own reference
204 * to the session is nulled and then we wait for the weak cache to
205 * be finalized.
206 *
207 * @see de.bea.domingo.DNotesFactory#dispose()
208 * @see de.bea.domingo.DNotesFactory#dispose(boolean)
209 * @see java.lang.ref.WeakReference
210 */
211 public void disposeInstance() {
212 disposeInstance(false);
213 }
214
215 /***
216 * <p>In this single threaded implementation, first the own reference
217 * to the session is nulled and then we wait for the weak cache to
218 * be finalized.
219 *
220 * <p>Equivalent to
221 * <code>{link {@link #disposeInstance(boolean) disposeInstance(false)}</code></p>.
222 *
223 * @param force indicates if disposal should happen even if still any
224 * strong or soft reference exists. if <code>false</code>,
225 * only weak references must remain.
226 *
227 * @see de.bea.domingo.DNotesFactory#dispose()
228 * @see de.bea.domingo.DNotesFactory#dispose(boolean)
229 * @see java.lang.ref.WeakReference
230 */
231 public void disposeInstance(final boolean force) {
232 System.gc();
233 recycleQueue();
234 fInternalSession = null;
235 if (force) {
236 disposeStrong();
237 } else {
238 disposeWeak();
239 }
240 if (fBaseCache.size() > 0) {
241 final int k = logUndisposedObjects();
242 if (k > 1) {
243 getMonitor().warn("There are still " + k + " undisposed objects in the object cache:");
244 } else {
245 getMonitor().warn("There is still one undisposed object in the object cache:");
246 }
247 if (k > 0) {
248 getMonitor().warn("Unable to dispose all objects.");
249 } else {
250 getMonitor().info("All objects in object cache disposed successfully.");
251 }
252 }
253 if (getMonitor().isDebugEnabled()) {
254 getMonitor().debug("DateTime counter is " + BaseProxy.getCountDateTime());
255 }
256 }
257
258 /***
259 * Disposes all objects that have only weak references.
260 * All objects that still have strong references, are not disposed.
261 */
262 private void disposeWeak() {
263 int tries = 0;
264 while (fBaseCache.size() > 0 && tries < MAX_DISPOSE_TRIES) {
265 tries++;
266 getMonitor().debug("Waiting for notes disposal. (" + fBaseCache.size() + " objects in queue)");
267 System.gc();
268 recycleQueue();
269 sleep(TIME_WAIT_FOR_GC);
270 }
271 }
272
273 /***
274 * Disposes all objects even if there are still strong references left.
275 * All objects that still have strong references, are not valid anymore afterwards.
276 */
277 private void disposeStrong() {
278 Collection values = fBaseCache.values();
279 while (values.size() > 0) {
280 try {
281 final Iterator objects = values.iterator();
282 while (objects.hasNext()) {
283 Object obj = objects.next();
284 if (obj != null) {
285 if (obj instanceof WeakReference) {
286 obj = ((WeakReference) obj).get();
287 }
288 if (obj != null) {
289 recycleLater(obj);
290 }
291 }
292 }
293 recycleQueue();
294 fBaseCache.clear();
295 } catch (ConcurrentModificationException e) {
296 getMonitor().debug("Concurrent modification in disposeStrong(); retry recycle");
297 }
298 }
299 }
300
301 /***
302 * Logs and counts all undisposed objects to the current monitor.
303 * @return number of undisposed objects
304 */
305 private int logUndisposedObjects() {
306 final Iterator iterator = fBaseCache.values().iterator();
307 int i = 0;
308 int k = 0;
309 while (iterator.hasNext()) {
310 Object obj = iterator.next();
311 i++;
312 if (obj != null) {
313 if (obj instanceof WeakReference) {
314 obj = ((WeakReference) obj).get();
315 }
316 if (obj != null) {
317 k = k + 1;
318 getMonitor().warn("undisposed object " + k + ": " + obj.getClass().getName() + "." + obj.toString());
319 }
320 }
321 }
322 return k;
323 }
324
325 /***
326 * Sleep some milliseconds unless interrupted.
327 *
328 * @param millis time to sleep in milliseconds
329 */
330 private synchronized void sleep(final int millis) {
331 try {
332 wait(millis);
333 } catch (InterruptedException e) {
334 return;
335 }
336 }
337
338 /***
339 * Recycles resources associated with an object.
340 *
341 * <p>Static delegation method to associated recycle strategy.</p>
342 *
343 * @param object the object to recycle
344 *
345 * @see de.bea.domingo.proxy.NotesRecycler#recycle(java.lang.Object)
346 */
347 void recycle(final Object object) {
348 if (fRecycler != null) {
349 fRecycler.recycle(object);
350 }
351 }
352
353 /***
354 * @see de.bea.domingo.proxy.NotesRecycler#recycleLater(java.lang.Object)
355 */
356 void recycleLater(final Object object) {
357 if (fRecycler != null) {
358 fRecycler.recycleLater(object);
359 }
360 }
361
362 /***
363 * @see de.bea.domingo.proxy.NotesRecycler#recycleQueue()
364 */
365 void recycleQueue() {
366 if (fRecycler != null) {
367 fRecycler.recycleQueue();
368 }
369 }
370
371
372
373
374
375 /***
376 * {@inheritDoc}
377 * @see de.bea.domingo.DNotesFactory#getSession()
378 */
379 public DSession getSession() throws DNotesRuntimeException {
380 if (fInternalSession == null) {
381 try {
382 preprocessMethod();
383 final Session session = NotesFactory.createSession();
384 fInternalSession = SessionProxy.getInstance(this, session, getMonitor());
385 setRecycler(session);
386 logSsession(session);
387 handleShutdownHook();
388 } catch (NotesException e) {
389 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
390 } catch (UnsatisfiedLinkError e) {
391 if (e.getMessage().indexOf("java.library.path") >= 0) {
392 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.installation.not.found"), e);
393 } else if (e.getMessage().indexOf("NGetWrapper") >= 0 || e.getMessage().indexOf("NCreateSession") >= 0) {
394 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.installation.not.found"), e);
395 } else {
396 throw new NotesProxyRuntimeException(e.getMessage(), e);
397 }
398 } catch (NoClassDefFoundError e) {
399 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.jar.missing.in.classpath"), e);
400 }
401 }
402 return fInternalSession;
403 }
404
405 /***
406 * {@inheritDoc}
407 * @see de.bea.domingo.DNotesFactory#getSession(java.lang.String)
408 */
409 public DSession getSession(final String serverUrl) throws DNotesRuntimeException {
410 DSession session = (DSession) fIiopSessions.get(serverUrl);
411 if (session == null) {
412 try {
413 preprocessMethod();
414 final Session notesSession = NotesFactory.createSession(serverUrl);
415 session = SessionProxy.getInstance(this, notesSession, getMonitor());
416 setRecycler(notesSession);
417 handleShutdownHook();
418 fIiopSessions.put(serverUrl, session);
419 } catch (NotesException e) {
420 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
421 } catch (NoClassDefFoundError e) {
422 if (e.getMessage().indexOf("lotus/domino/cso/Session") >= 0) {
423 throw new NotesProxyRuntimeException(RESOURCES.getString("ncso.missing"), e);
424 }
425 }
426 }
427 return session;
428 }
429
430 /***
431 * {@inheritDoc}
432 * @see de.bea.domingo.DNotesFactory#getSession(java.lang.String, java.lang.String, java.lang.String)
433 */
434 public DSession getSession(final String host, final String user, final String passwd) throws DNotesRuntimeException {
435 DSession session = (DSession) fIiopSessions.get(host + ":" + user);
436 if (session == null || !session.isValid()) {
437 try {
438 preprocessMethod();
439 final Session notesSession = NotesFactory.createSession(host, user, passwd);
440 session = SessionProxy.getInstance(this, notesSession, getMonitor());
441 setRecycler(notesSession);
442 fIiopSessions.put(host + ":" + user, session);
443 } catch (NotesException e) {
444 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
445 } catch (NoClassDefFoundError e) {
446 if (e.getMessage().indexOf("lotus/domino/cso/Session") >= 0) {
447 throw new NotesProxyRuntimeException(RESOURCES.getString("ncso.missing"), e);
448 } else {
449 throw e;
450 }
451 }
452 }
453 return session;
454 }
455
456 /***
457 * {@inheritDoc}
458 * @see de.bea.domingo.DNotesFactory#getSessionSSL(java.lang.String, java.lang.String, java.lang.String)
459 */
460 public DSession getSessionSSL(final String host, final String user, final String passwd) throws DNotesRuntimeException {
461 String[] args = new String[1];
462 args[0] = "-ORBEnableSSLSecurity";
463 return getSession(host, args, user, passwd);
464 }
465
466 /***
467 * {@inheritDoc}
468 * @see de.bea.domingo.DNotesFactory#getSession(java.lang.String, java.lang.String[], java.lang.String, java.lang.String)
469 */
470 public DSession getSession(final String host, final String[] args, final String user, final String passwd)
471 throws DNotesRuntimeException {
472 DSession session = (DSession) fIiopSessions.get(host + ":" + user + ":" + args);
473 if (session == null || !session.isValid()) {
474 try {
475 preprocessMethod();
476 final Session notesSession = NotesFactory.createSession(host, args, user, passwd);
477 session = SessionProxy.getInstance(this, notesSession, getMonitor());
478 setRecycler(notesSession);
479 fIiopSessions.put(host + ":" + user, session);
480 } catch (NotesException e) {
481 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
482 } catch (NoClassDefFoundError e) {
483 if (e.getMessage().indexOf("lotus/domino/cso/Session") >= 0) {
484 throw new NotesProxyRuntimeException(RESOURCES.getString("ncso.missing"), e);
485 }
486 }
487 }
488 return session;
489 }
490
491 /***
492 * {@inheritDoc}
493 * @see de.bea.domingo.DNotesFactory#getSession(java.applet.Applet, java.lang.String, java.lang.String)
494 */
495 public DSession getSession(final Applet applet, final String user, final String passwd) throws DNotesRuntimeException {
496 DSession session = null;
497 try {
498 preprocessMethod();
499 final Session notesSession = NotesFactory.createSession(applet, user, passwd);
500 session = SessionProxy.getInstance(this, notesSession, getMonitor());
501 setRecycler(notesSession);
502 } catch (NotesException e) {
503 if (e.id == NotesError.NOTES_ERR_SESOPEN_FAILED) {
504 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
505 } else {
506 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
507 }
508 } catch (NoClassDefFoundError e) {
509 if (e.getMessage().indexOf("lotus/domino/cso/Session") >= 0) {
510 throw new NotesProxyRuntimeException(RESOURCES.getString("ncso.missing"), e);
511 }
512 }
513 return session;
514 }
515
516 /***
517 * {@inheritDoc}
518 * @see de.bea.domingo.DNotesFactory#getSession(java.lang.Object)
519 */
520 public DSession getSession(final Object notesSession) throws DNotesRuntimeException {
521 return SessionProxy.getInstance(this, (Session) notesSession, getMonitor());
522 }
523
524 /***
525 * {@inheritDoc}
526 * @see de.bea.domingo.DNotesFactory#getSessionWithFullAccess()
527 */
528 public DSession getSessionWithFullAccess() throws DNotesRuntimeException {
529 if (fInternalSession == null) {
530 try {
531 preprocessMethod();
532 final Session session = NotesFactory.createSessionWithFullAccess();
533 fInternalSession = SessionProxy.getInstance(this, session, getMonitor());
534 setRecycler(session);
535 logSsession(session);
536 handleShutdownHook();
537 } catch (NotesException e) {
538 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
539 } catch (UnsatisfiedLinkError e) {
540 if (e.getMessage().indexOf("java.library.path") >= 0) {
541 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.installation.not.found"), e);
542 } else if (e.getMessage().indexOf("NGetWrapper") >= 0 || e.getMessage().indexOf("NCreateSession") >= 0) {
543 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.installation.not.found"), e);
544 } else {
545 throw new NotesProxyRuntimeException(e.getMessage(), e);
546 }
547 } catch (NoClassDefFoundError e) {
548 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.jar.missing.in.classpath"), e);
549 }
550 }
551 return fInternalSession;
552 }
553
554 /***
555 * {@inheritDoc}
556 * @see de.bea.domingo.DNotesFactory#getSessionWithFullAccess(java.lang.String)
557 */
558 public DSession getSessionWithFullAccess(final String password) throws DNotesRuntimeException {
559 if (fInternalSession == null) {
560 try {
561 preprocessMethod();
562 final Session session = NotesFactory.createSessionWithFullAccess(password);
563 fInternalSession = SessionProxy.getInstance(this, session, getMonitor());
564 setRecycler(session);
565 logSsession(session);
566 handleShutdownHook();
567 } catch (NotesException e) {
568 throw new NotesProxyRuntimeException(RESOURCES.getString("cannot.create.session"), new DominoException(e));
569 } catch (UnsatisfiedLinkError e) {
570 if (e.getMessage().indexOf("java.library.path") >= 0) {
571 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.installation.not.found"), e);
572 } else if (e.getMessage().indexOf("NGetWrapper") >= 0 || e.getMessage().indexOf("NCreateSession") >= 0) {
573 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.installation.not.found"), e);
574 } else {
575 throw new NotesProxyRuntimeException(e.getMessage(), e);
576 }
577 } catch (NoClassDefFoundError e) {
578 throw new NotesProxyRuntimeException(RESOURCES.getString("notes.jar.missing.in.classpath"), e);
579 }
580 }
581 return fInternalSession;
582 }
583
584 /***
585 * If requested and possible, adds a shutdown hook to dispose domingo
586 * on termination of the virtual machine.
587 */
588 private void handleShutdownHook() {
589 final boolean shutdownhook = DNotesFactory.getBooleanProperty("de.bea.domingo.shutdownhook", true);
590 if (shutdownhook) {
591 if (checkPermission("shutdownHooks")) {
592 Runtime.getRuntime().addShutdownHook(new DNotesShutdownThread());
593 } else {
594 getMonitor().warn(RESOURCES.getString("shutdownhook.not.allowed"));
595 }
596 }
597 }
598
599 /***
600 * Checks if the requested access, specified by the given permission name,
601 * is permitted based on the security policy currently in effect.
602 *
603 * @param name the name of the RuntimePermission.
604 * @return <code>true</code> if access is permitted based on the current
605 * security policy, else <code>false</code>
606 * @see java.lang.SecurityManager#checkPermission(java.security.Permission)
607 */
608 private boolean checkPermission(final String name) {
609 final SecurityManager sm = System.getSecurityManager();
610 if (sm == null) {
611 return true;
612 }
613 try {
614 sm.checkPermission(new RuntimePermission(name));
615 } catch (SecurityException e) {
616 return false;
617 }
618 return true;
619 }
620
621 /***
622 * Logs information of a session to the current monitor.
623 *
624 * @param session a session
625 * @throws NotesException if any problem occured with the session
626 */
627 private void logSsession(final Session session) throws NotesException {
628 final DNotesMonitor monitor = getMonitor();
629 String currentVersion = "(unknown version)";
630 try {
631 currentVersion = session.getNotesVersion();
632 } catch (NotesException e) {
633 monitor.warn(RESOURCES.getString("cannot.get.notes.version"), new DominoException(e));
634 }
635 if (session.getClass().getName().equals("lotus.domino.cso.Session")) {
636 monitor.info(RESOURCES.getString("connect.to.domino.1", currentVersion));
637 } else {
638 monitor.info(RESOURCES.getString("connect.to.notes.1", currentVersion));
639 }
640 monitor.debug(RESOURCES.getString("local.session.established"));
641 monitor.debug(" " + RESOURCES.getString("notes.user") + ": " + session.getUserName());
642 monitor.debug(" " + RESOURCES.getString("notes.version") + ": " + session.getNotesVersion());
643 monitor.debug(" " + RESOURCES.getString("notes.platform") + ": " + session.getPlatform());
644 monitor.debug(" " + RESOURCES.getString("notes.data") + ": " + session.getEnvironmentString("Directory", true));
645 }
646
647 /***
648 * @see de.bea.domingo.DNotesFactory#sinitThread()
649 */
650 public void sinitThread() {
651 getMonitor().debug(RESOURCES.getString("thread.initialize"));
652 try {
653 NotesThread.sinitThread();
654 } catch (UnsatisfiedLinkError e) {
655 getMonitor().debug("Local Notes Client not accessable; only remote connections possible");
656 } catch (NoClassDefFoundError e) {
657 getMonitor().debug("Local Notes Client not accessable; only remote connections possible");
658 }
659 }
660
661 /***
662 * @see de.bea.domingo.DNotesFactory#stermThread()
663 */
664 public void stermThread() {
665 getMonitor().debug(RESOURCES.getString("thread.terminate"));
666 try {
667 NotesThread.stermThread();
668 } catch (UnsatisfiedLinkError e) {
669 getMonitor().debug("Local Notes Client not accessable.");
670 } catch (NoClassDefFoundError e) {
671 getMonitor().debug("Local Notes Client not accessable.");
672 }
673 }
674
675 /***
676 * Preprocessing before each method invocation.
677 */
678 void preprocessMethod() {
679 final int size1 = getBaseCache().size();
680 if (fCacheThreshold != 0) {
681 if (size1 > fCacheThreshold) {
682 getMonitor().debug("baseCache.size = " + size1 + "; recycle queue now");
683 System.gc();
684 }
685 }
686 recycleQueue();
687 final int size2 = getBaseCache().size();
688 if (size1 != size2) {
689 getMonitor().debug("baseCache.size = " + size2 + "; after recycling queue");
690 }
691 }
692
693 /***
694 * {@inheritDoc}
695 * @see de.bea.domingo.DNotesFactory#getMonitor()
696 */
697 public DNotesMonitor getMonitor() {
698 return fMonitor;
699 }
700
701 /***
702 * {@inheritDoc}
703 * @see de.bea.domingo.DNotesFactory#setMonitor(de.bea.domingo.DNotesMonitor)
704 */
705 public void setMonitor(final DNotesMonitor theMonitor) {
706 this.fMonitor = theMonitor;
707 }
708 }