001: /*=============================================================================
002: * Copyright Texas Instruments 2002. All Rights Reserved.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package ti.chimera;
020:
021: import java.lang.ref.Reference;
022: import java.lang.ref.WeakReference;
023: import java.lang.ref.ReferenceQueue;
024: import java.util.Hashtable;
025:
026: /**
027: * Ignore this... instead use Plugin$ServiceFactory... the implementation of
028: * that class was simply broken out into this file to keep the file size of
029: * Plugin.java under control.
030: *
031: * @author Rob Clark
032: * @version 0.1
033: */
034: abstract class ServiceFactoryImpl {
035: /**
036: * The plugin this service is part of. If this were an inner-class of
037: * Plugin, this field wouldn't be needed.
038: */
039: private Plugin plugin;
040:
041: /**
042: * The reference to the the service. If someone requests a service, and
043: * there is an outstanding reference to the service, then don't bother
044: * calling {@link #createService}.
045: */
046: private Reference serviceReference;
047:
048: /**
049: * The name of the service.
050: */
051: private String name;
052:
053: /**
054: * This bogus unmanaged resource is installed whenever there is an
055: * outstanding reference to the service, in order to ensure that the
056: * plugin is always active when someone holds a reference to a service
057: * provided by the plugin.
058: */
059: private Resource serviceResource = new Resource(false) {
060: public void install() {
061: }
062:
063: public void uninstall() {
064: }
065:
066: public String toString() {
067: return "[ServiceResource: " + getName() + "]";
068: }
069: };
070:
071: private static ReferenceQueue serviceReferenceQueue = new ReferenceQueue();
072: private static Hashtable serviceReferenceTable = new Hashtable(); // maps ref -> factory
073:
074: static {
075: oscript.util.WorkerThread.addRunnable(new Runnable() {
076: public void run() {
077: Reference ref;
078: while ((ref = serviceReferenceQueue.poll()) != null) {
079: ServiceFactoryImpl f = (ServiceFactoryImpl) (serviceReferenceTable
080: .get(ref));
081: if (f != null)
082: f.cleanup();
083: }
084: }
085: }, 500);
086: }
087:
088: /**
089: * Class Constructor.
090: */
091: protected ServiceFactoryImpl(Plugin plugin) {
092: this .plugin = plugin;
093: }
094:
095: /**
096: * Get the name of the service this is a factory for.
097: *
098: * @return the service name
099: */
100: public String getName() {
101: if (name == null)
102: name = createService().getName();
103: return name;
104: }
105:
106: /**
107: * Get the service that this factory creates. This may return an existing
108: * service instance, or may create a new one. It will ensure that the
109: * plugin is active as long as someone holds a reference to the service
110: * instance.
111: *
112: * @return the <code>Service</code> object
113: */
114: public synchronized Service getService() {
115: Service service = null;
116:
117: if (serviceReference != null)
118: service = (Service) (serviceReference.get());
119:
120: if (service == null) {
121: /* The previous service object has been cleared, but we don't know if
122: * the "service cleanup" thread has gotten around to calling cleanup()
123: * yet, so we do that here as well, just in case.
124: */
125: cleanup();
126:
127: // ensure plugin is active *before* calling createService():
128: plugin.addResource(serviceResource);
129:
130: service = createService();
131:
132: serviceReference = new WeakReference(service,
133: serviceReferenceQueue);
134: serviceReferenceTable.put(serviceReference, this );
135: }
136:
137: return service;
138: }
139:
140: /**
141: * called from thread reading from reference queue when our service is
142: * no longer reference
143: */
144: private synchronized void cleanup() {
145: if ((serviceReference != null)
146: && (serviceReference.get() == null)) {
147: serviceReferenceTable.remove(serviceReference);
148: serviceReference = null;
149: plugin.removeResource(serviceResource);
150: }
151: }
152:
153: /**
154: * For debug...
155: */
156: public String toString() {
157: return "[ServiceFactory: " + getName() + "]";
158: }
159:
160: /**
161: * Create the service this object is a factory for. This should create a new
162: * instance of the service everytime that it gets called, because nothing
163: * other than the client of the service should hold a reference to the
164: * service.
165: *
166: * @return a newly instantiated <code>Service</code> object.
167: */
168: public abstract Service createService();
169: }
170:
171: /*
172: * Local Variables:
173: * tab-width: 2
174: * indent-tabs-mode: nil
175: * mode: java
176: * c-indentation-style: java
177: * c-basic-offset: 2
178: * eval: (c-set-offset 'substatement-open '0)
179: * eval: (c-set-offset 'case-label '+)
180: * eval: (c-set-offset 'inclass '+)
181: * eval: (c-set-offset 'inline-open '0)
182: * End:
183: */
|