KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > content > transform > ContentTransformerRegistry


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.content.transform;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.concurrent.locks.Lock JavaDoc;
25 import java.util.concurrent.locks.ReadWriteLock JavaDoc;
26 import java.util.concurrent.locks.ReentrantReadWriteLock JavaDoc;
27
28 import org.alfresco.error.AlfrescoRuntimeException;
29 import org.alfresco.repo.content.MimetypeMap;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.springframework.util.Assert;
33
34 /**
35  * Holds and provides the most appropriate content transformer for
36  * a particular source and target mimetype transformation request.
37  * <p>
38  * The transformers themselves are used to determine the applicability
39  * of a particular transformation.
40  *
41  * @see org.alfresco.repo.content.transform.ContentTransformer
42  *
43  * @author Derek Hulley
44  */

45 public class ContentTransformerRegistry
46 {
47     private static final Log logger = LogFactory.getLog(ContentTransformerRegistry.class);
48     
49     private List JavaDoc<ContentTransformer> transformers;
50     private MimetypeMap mimetypeMap;
51     /** Cache of previously used transactions */
52     private Map JavaDoc<TransformationKey, List JavaDoc<ContentTransformer>> transformationCache;
53     private short accessCount;
54     /** Controls read access to the transformation cache */
55     private Lock JavaDoc transformationCacheReadLock;
56     /** controls write access to the transformation cache */
57     private Lock JavaDoc transformationCacheWriteLock;
58     
59     /**
60      * @param mimetypeMap all the mimetypes available to the system
61      */

62     public ContentTransformerRegistry(MimetypeMap mimetypeMap)
63     {
64         Assert.notNull(mimetypeMap, "The MimetypeMap is mandatory");
65         this.mimetypeMap = mimetypeMap;
66         
67         this.transformers = new ArrayList JavaDoc<ContentTransformer>(10);
68         transformationCache = new HashMap JavaDoc<TransformationKey, List JavaDoc<ContentTransformer>>(17);
69         
70         accessCount = 0;
71         // create lock objects for access to the cache
72
ReadWriteLock JavaDoc transformationCacheLock = new ReentrantReadWriteLock JavaDoc();
73         transformationCacheReadLock = transformationCacheLock.readLock();
74         transformationCacheWriteLock = transformationCacheLock.writeLock();
75     }
76     
77     /**
78      * Register an individual transformer against a specific transformation. This transformation
79      * will take precedence over any of the generally-registered transformers.
80      *
81      * @param key the mapping from one mimetype to the next
82      * @param transformer the content transformer
83      */

84     public void addExplicitTransformer(TransformationKey key, ContentTransformer transformer)
85     {
86         transformationCache.put(key, Collections.singletonList(transformer));
87         // done
88
if (logger.isDebugEnabled())
89         {
90             logger.debug("Registered explicit transformation: \n" +
91                     " key: " + key + "\n" +
92                     " transformer: " + transformer);
93         }
94     }
95     
96     /**
97      * Registers an individual transformer that can be queried to check for applicability.
98      *
99      * @param transformer a content transformer
100      */

101     public void addTransformer(ContentTransformer transformer)
102     {
103         transformers.add(transformer);
104         // done
105
if (logger.isDebugEnabled())
106         {
107             logger.debug("Registered general transformer: \n" +
108                     " transformer: " + transformer);
109         }
110     }
111
112     /**
113      * Resets the transformation cache. This allows a fresh analysis of the best
114      * conversions based on actual average performance of the transformers.
115      */

116     public void resetCache()
117     {
118         // get a write lock on the cache
119
transformationCacheWriteLock.lock();
120         try
121         {
122             transformationCache.clear();
123             accessCount = 0;
124         }
125         finally
126         {
127             transformationCacheWriteLock.unlock();
128         }
129         // done
130
if (logger.isDebugEnabled())
131         {
132             logger.debug("Content transformation cache reset");
133         }
134     }
135     
136     /**
137      * Gets the best transformer possible. This is a combination of the most reliable
138      * and the most performant transformer.
139      * <p>
140      * The result is cached for quicker access next time.
141      *
142      * @param sourceMimetype the source mimetype of the transformation
143      * @param targetMimetype the target mimetype of the transformation
144      * @return Returns a content transformer that can perform the desired
145      * transformation or null if no transformer could be found that would do it.
146      */

147     public ContentTransformer getTransformer(String JavaDoc sourceMimetype, String JavaDoc targetMimetype)
148     {
149         // check that the mimetypes are valid
150
if (!mimetypeMap.getMimetypes().contains(sourceMimetype))
151         {
152             throw new AlfrescoRuntimeException("Unknown source mimetype: " + sourceMimetype);
153         }
154         if (!mimetypeMap.getMimetypes().contains(targetMimetype))
155         {
156             throw new AlfrescoRuntimeException("Unknown target mimetype: " + targetMimetype);
157         }
158         
159         TransformationKey key = new TransformationKey(sourceMimetype, targetMimetype);
160         List JavaDoc<ContentTransformer> transformers = null;
161         transformationCacheReadLock.lock();
162         try
163         {
164             if (transformationCache.containsKey(key))
165             {
166                 // the translation has been requested before
167
// it might have been null
168
transformers = transformationCache.get(key);
169             }
170         }
171         finally
172         {
173             transformationCacheReadLock.unlock();
174         }
175         
176         if (transformers == null)
177         {
178             // the translation has not been requested before
179
// get a write lock on the cache
180
// no double check done as it is not an expensive task
181
transformationCacheWriteLock.lock();
182             try
183             {
184                 // find the most suitable transformer - may be empty list
185
transformers = findTransformers(sourceMimetype, targetMimetype);
186                 // store the result even if it is null
187
transformationCache.put(key, transformers);
188             }
189             finally
190             {
191                 transformationCacheWriteLock.unlock();
192             }
193         }
194         // select the most performant transformer
195
long bestTime = -1L;
196         ContentTransformer bestTransformer = null;
197         for (ContentTransformer transformer : transformers)
198         {
199             long transformationTime = transformer.getTransformationTime();
200             // is it better?
201
if (bestTransformer == null || transformationTime < bestTime)
202             {
203                 bestTransformer = transformer;
204                 bestTime = transformationTime;
205             }
206         }
207         // done
208
return bestTransformer;
209     }
210     
211     /**
212      * Gets all transformers, of equal reliability, that can perform the requested transformation.
213      *
214      * @return Returns best transformer for the translation - null if all
215      * score 0.0 on reliability
216      */

217     private List JavaDoc<ContentTransformer> findTransformers(String JavaDoc sourceMimetype, String JavaDoc targetMimetype)
218     {
219         // search for a simple transformer that can do the job
220
List JavaDoc<ContentTransformer> transformers = findDirectTransformers(sourceMimetype, targetMimetype);
221         // get the complex transformers that can do the job
222
List JavaDoc<ContentTransformer> complexTransformers = findComplexTransformer(sourceMimetype, targetMimetype);
223         transformers.addAll(complexTransformers);
224         // done
225
if (logger.isDebugEnabled())
226         {
227             logger.debug("Searched for transformer: \n" +
228                     " source mimetype: " + sourceMimetype + "\n" +
229                     " target mimetype: " + targetMimetype + "\n" +
230                     " transformers: " + transformers);
231         }
232         return transformers;
233     }
234     
235     /**
236      * Loops through the content transformers and picks the ones with the highest reliabilities.
237      * <p>
238      * Where there are several transformers that are equally reliable, they are all returned.
239      *
240      * @return Returns the most reliable transformers for the translation - empty list if there
241      * are none.
242      */

243     private List JavaDoc<ContentTransformer> findDirectTransformers(String JavaDoc sourceMimetype, String JavaDoc targetMimetype)
244     {
245         double maxReliability = 0.0;
246         long leastTime = 100000L; // 100 seconds - longer than anyone would think of waiting
247
List JavaDoc<ContentTransformer> bestTransformers = new ArrayList JavaDoc<ContentTransformer>(2);
248         // loop through transformers
249
for (ContentTransformer transformer : this.transformers)
250         {
251             double reliability = transformer.getReliability(sourceMimetype, targetMimetype);
252             if (reliability <= 0.0)
253             {
254                 // it is unusable
255
continue;
256             }
257             else if (reliability < maxReliability)
258             {
259                 // it is not the best one to use
260
continue;
261             }
262             else if (reliability == maxReliability)
263             {
264                 // it is as reliable as a previous transformer
265
}
266             else
267             {
268                 // it is better than any previous transformer - wipe them
269
bestTransformers.clear();
270                 maxReliability = reliability;
271             }
272             // add the transformer to the list
273
bestTransformers.add(transformer);
274         }
275         // done
276
return bestTransformers;
277     }
278     
279     /**
280      * Uses a list of known mimetypes to build transformations from several direct transformations.
281      */

282     private List JavaDoc<ContentTransformer> findComplexTransformer(String JavaDoc sourceMimetype, String JavaDoc targetMimetype)
283     {
284         // get a complete list of mimetypes
285
// TODO: Build complex transformers by searching for transformations by mimetype
286
return Collections.emptyList();
287     }
288     
289     /**
290      * Recursive method to build up a list of content transformers
291      */

292     private void buildTransformer(List JavaDoc<ContentTransformer> transformers,
293             double reliability,
294             List JavaDoc<String JavaDoc> touchedMimetypes,
295             String JavaDoc currentMimetype,
296             String JavaDoc targetMimetype)
297     {
298         throw new UnsupportedOperationException JavaDoc();
299     }
300     
301     /**
302      * A key for a combination of a source and target mimetype
303      */

304     public static class TransformationKey
305     {
306         private final String JavaDoc sourceMimetype;
307         private final String JavaDoc targetMimetype;
308         private final String JavaDoc key;
309         
310         public TransformationKey(String JavaDoc sourceMimetype, String JavaDoc targetMimetype)
311         {
312             this.key = (sourceMimetype + "_" + targetMimetype);
313             this.sourceMimetype = sourceMimetype;
314             this.targetMimetype = targetMimetype;
315         }
316         
317         public String JavaDoc getSourceMimetype()
318         {
319             return sourceMimetype;
320         }
321         public String JavaDoc getTargetMimetype()
322         {
323             return targetMimetype;
324         }
325
326         @Override JavaDoc
327         public boolean equals(Object JavaDoc obj)
328         {
329             if (obj == null)
330             {
331                 return false;
332             }
333             else if (this == obj)
334             {
335                 return true;
336             }
337             else if (!(obj instanceof TransformationKey))
338             {
339                 return false;
340             }
341             TransformationKey that = (TransformationKey) obj;
342             return this.key.equals(that.key);
343         }
344         @Override JavaDoc
345         public int hashCode()
346         {
347             return key.hashCode();
348         }
349     }
350 }
351
Popular Tags