001 package gate.util.spring;
002
003 import java.io.IOException;
004 import java.lang.ref.WeakReference;
005 import java.lang.reflect.Proxy;
006 import java.util.ArrayList;
007 import java.util.Collections;
008 import java.util.List;
009
010 import gate.Controller;
011 import gate.Corpus;
012 import gate.CorpusController;
013 import gate.Document;
014 import gate.Factory;
015 import gate.Gate;
016 import gate.LanguageAnalyser;
017 import gate.LanguageResource;
018 import gate.ProcessingResource;
019 import gate.Resource;
020 import gate.creole.ConditionalController;
021 import gate.creole.ResourceInstantiationException;
022 import gate.creole.gazetteer.Gazetteer;
023 import gate.creole.ontology.Ontology;
024 import gate.util.GateException;
025
026 import org.springframework.beans.factory.DisposableBean;
027 import org.springframework.beans.factory.FactoryBean;
028
029 /**
030 * Spring factory bean to create duplicate copies of a GATE resource.
031 * This bean would typically be declared with singleton scope, but the
032 * factory produces a new duplicate of its template resource each time
033 * getBean is called (or each time it is injected as a dependency).
034 */
035 public class DuplicateResourceFactoryBean extends GateAwareObject implements
036 FactoryBean,
037 DisposableBean {
038
039 /**
040 * The template resource which we will duplicate.
041 */
042 private Resource templateResource;
043
044 /**
045 * Should we return the template itself the first time
046 * {@link #getObject()} is called, or should we keep it for use only
047 * as a template and just return duplicates?
048 */
049 private boolean returnTemplate = false;
050
051 /**
052 * Customisers that are applied to the duplicated resource before it
053 * is returned.
054 */
055 private List<ResourceCustomiser> customisers;
056
057 /**
058 * Set the template resource that this factory bean will duplicate.
059 */
060 public void setTemplate(Resource template) {
061 this.templateResource = template;
062 }
063
064 /**
065 * Should this factory bean return the template resource itself the
066 * first time {@link #getObject()} is called, or should it always
067 * return a duplicate, keeping the template in pristine condition.
068 * Generally, if the duplicates will all be created up-front, and
069 * there are no configured customisers, then it is safe to set this
070 * option to true. In cases where the duplicates may be created
071 * asynchronously (possibly creating one duplicate while another one
072 * is in use in a different thread) or may be customised after
073 * creation it is safer to set this option to false (the default) to
074 * keep the template pristine and always return duplicates.
075 */
076 public void setReturnTemplate(boolean returnTemplate) {
077 this.returnTemplate = returnTemplate;
078 }
079
080 /**
081 * Optional customisers that will be applied to the duplicate resource
082 * before it is returned. If customisers are specified then it is
083 * strongly recommended to leave the returnTemplate option set to
084 * <code>false</code>.
085 */
086 public void setCustomisers(List<ResourceCustomiser> customisers) {
087 this.customisers = customisers;
088 }
089
090 /**
091 * A list of weak references to the duplicates that have been
092 * returned, so they can be freed when this factory bean is disposed.
093 */
094 private List<WeakReference<Resource>> resourcesReturned = Collections
095 .synchronizedList(new ArrayList<WeakReference<Resource>>());
096
097 private Class<?> typeClass = null;
098
099 public Object getObject() throws Exception {
100 ensureGateInit();
101 Resource toReturn = null;
102 if(returnTemplate) {
103 synchronized(resourcesReturned) {
104 if(resourcesReturned.isEmpty()) {
105 resourcesReturned.add(new WeakReference<Resource>(templateResource));
106 toReturn = templateResource;
107 }
108 }
109 }
110
111 if(toReturn == null) {
112 toReturn = Factory.duplicate(templateResource);
113 }
114
115 if(customisers != null) {
116 for(ResourceCustomiser c : customisers) {
117 try {
118 c.customiseResource(toReturn);
119 }
120 catch(GateException gx) {
121 throw gx;
122 }
123 catch(IOException ix) {
124 throw ix;
125 }
126 catch(RuntimeException rx) {
127 throw rx;
128 }
129 catch(Exception e) {
130 throw new ResourceInstantiationException(
131 "Exception in resource customiser", e);
132 }
133 }
134 }
135
136 if(toReturn != templateResource) {
137 resourcesReturned.add(new WeakReference<Resource>(toReturn));
138 }
139
140 return toReturn;
141 }
142
143 /**
144 * Returns a proxy class that implements the same set of GATE
145 * interfaces as the template resource. See
146 * {@link Factory#duplicate(Resource)} for the list of interfaces that
147 * will be considered.
148 */
149 public Class<?> getObjectType() {
150 if(templateResource != null && typeClass == null) {
151 List<Class<?>> interfaces = new ArrayList<Class<?>>();
152 interfaces.add(Resource.class);
153 if(templateResource instanceof ProcessingResource) {
154 interfaces.add(ProcessingResource.class);
155 }
156 if(templateResource instanceof LanguageAnalyser) {
157 interfaces.add(LanguageAnalyser.class);
158 }
159 if(templateResource instanceof Gazetteer) {
160 interfaces.add(Gazetteer.class);
161 }
162 if(templateResource instanceof Controller) {
163 interfaces.add(Controller.class);
164 }
165 if(templateResource instanceof CorpusController) {
166 interfaces.add(CorpusController.class);
167 }
168 if(templateResource instanceof ConditionalController) {
169 interfaces.add(ConditionalController.class);
170 }
171 if(templateResource instanceof LanguageResource) {
172 interfaces.add(LanguageResource.class);
173 }
174 if(templateResource instanceof Ontology) {
175 interfaces.add(Ontology.class);
176 }
177 if(templateResource instanceof Document) {
178 interfaces.add(Document.class);
179 }
180 if(templateResource instanceof Corpus) {
181 interfaces.add(Corpus.class);
182 }
183 typeClass = Proxy.getProxyClass(Gate.getClassLoader(), interfaces
184 .toArray(new Class<?>[interfaces.size()]));
185 }
186 return typeClass;
187 }
188
189 /**
190 * This factory is not a singleton - it produces a new object each
191 * time {@link #getObject()} is called.
192 */
193 public boolean isSingleton() {
194 return false;
195 }
196
197 /**
198 * Delete the duplicates we have returned, unless they have already
199 * been freed.
200 */
201 public void destroy() {
202 for(WeakReference<Resource> res : resourcesReturned) {
203 Resource r = res.get();
204 if(r != null) {
205 Factory.deleteResource(r);
206 }
207 }
208 }
209 }
|