KickJava   Java API By Example, From Geeks To Geeks.

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


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.List JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import org.alfresco.error.AlfrescoRuntimeException;
25 import org.alfresco.service.cmr.repository.ContentAccessor;
26 import org.alfresco.service.cmr.repository.ContentIOException;
27 import org.alfresco.service.cmr.repository.ContentReader;
28 import org.alfresco.service.cmr.repository.ContentWriter;
29 import org.alfresco.service.cmr.repository.MimetypeService;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 /**
34  * Provides basic services for {@link org.alfresco.repo.content.transform.ContentTransformer}
35  * implementations.
36  * <p>
37  * This class maintains the performance measures for the transformers as well, making sure that
38  * there is an extra penalty for transformers that fail regularly.
39  *
40  * @author Derek Hulley
41  */

42 public abstract class AbstractContentTransformer implements ContentTransformer
43 {
44     private static final Log logger = LogFactory.getLog(AbstractContentTransformer.class);
45     
46     private MimetypeService mimetypeService;
47     private ContentTransformerRegistry registry;
48     private List JavaDoc<ContentTransformerRegistry.TransformationKey> explicitTransformations;
49     private double averageTime = 0.0;
50     private long count = 0L;
51     
52     /**
53      * All transformers start with an average transformation time of 0.0ms.
54      */

55     protected AbstractContentTransformer()
56     {
57         averageTime = 0.0;
58         explicitTransformations = new ArrayList JavaDoc<ContentTransformerRegistry.TransformationKey>(0);
59     }
60
61     /**
62      * The registry to auto-register with
63      *
64      * @param registry the transformer registry
65      */

66     public void setRegistry(ContentTransformerRegistry registry)
67     {
68         this.registry = registry;
69     }
70
71     /**
72      * Helper setter of the mimetype service. This is not always required.
73      *
74      * @param mimetypeService
75      */

76     public void setMimetypeService(MimetypeService mimetypeService)
77     {
78         this.mimetypeService = mimetypeService;
79     }
80
81     /**
82      * @return Returns the mimetype helper
83      */

84     protected MimetypeService getMimetypeService()
85     {
86         return mimetypeService;
87     }
88
89     /**
90      * @return Returns the explicit transformations that were enabled for this transformer
91      */

92     protected List JavaDoc<ContentTransformerRegistry.TransformationKey> getExplicitTransformations()
93     {
94         return explicitTransformations;
95     }
96
97     /**
98      * Set the transformations that this transformer can do regardless of what it returns
99      * via the {@link ContentTransformer#getReliability(String, String) reliability check}.
100      *
101      * @param explicitTransformations explicit key mappings
102      */

103     public void setExplicitTransformations(List JavaDoc<ContentTransformerRegistry.TransformationKey> explicitTransformations)
104     {
105         this.explicitTransformations = explicitTransformations;
106     }
107
108     @Override JavaDoc
109     public String JavaDoc toString()
110     {
111         StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
112         sb.append(this.getClass().getSimpleName())
113           .append("[ average=").append((long)averageTime).append("ms")
114           .append("]");
115         return sb.toString();
116     }
117     
118     /**
119      * Registers this instance with the {@link #setRegistry(ContentTransformerRegistry) registry}
120      * if it is present.
121      */

122     public void register()
123     {
124         if (registry == null)
125         {
126             if (registry == null)
127             {
128                 logger.warn("Property 'registry' has not been set. Ignoring auto-registration: \n" +
129                         " transformer: " + this);
130                 return;
131             }
132             return;
133         }
134         // first register any explicit transformations
135
if (explicitTransformations != null)
136         {
137             for (ContentTransformerRegistry.TransformationKey key : explicitTransformations)
138             {
139                 registry.addExplicitTransformer(key, this);
140             }
141         }
142         // register this instance for the fallback case
143
registry.addTransformer(this);
144     }
145     
146     /**
147      * Convenience to fetch and check the mimetype for the given content
148      *
149      * @param content the reader/writer for the content
150      * @return Returns the mimetype for the content
151      * @throws AlfrescoRuntimeException if the content doesn't have a mimetype
152      */

153     protected String JavaDoc getMimetype(ContentAccessor content)
154     {
155         String JavaDoc mimetype = content.getMimetype();
156         if (mimetype == null)
157         {
158             throw new AlfrescoRuntimeException("Mimetype is mandatory for transformation: " + content);
159         }
160         // done
161
return mimetype;
162     }
163     
164     /**
165      * Convenience method to check the reliability of a transformation
166      *
167      * @param reader
168      * @param writer
169      * @throws AlfrescoRuntimeException if the reliability isn't > 0
170      */

171     protected void checkReliability(ContentReader reader, ContentWriter writer)
172     {
173         String JavaDoc sourceMimetype = getMimetype(reader);
174         String JavaDoc targetMimetype = getMimetype(writer);
175         double reliability = getReliability(sourceMimetype, targetMimetype);
176         if (reliability <= 0.0)
177         {
178             throw new AlfrescoRuntimeException("Zero scoring transformation attempted: \n" +
179                     " reader: " + reader + "\n" +
180                     " writer: " + writer);
181         }
182         // it all checks out OK
183
}
184
185     /**
186      * Method to be implemented by subclasses wishing to make use of the common infrastructural code
187      * provided by this class.
188      *
189      * @param reader the source of the content to transform
190      * @param writer the target to which to write the transformed content
191      * @param options a map of options to use when performing the transformation. The map
192      * will never be null.
193      * @throws Exception exceptions will be handled by this class - subclasses can throw anything
194      */

195     protected abstract void transformInternal(
196             ContentReader reader,
197             ContentWriter writer,
198             Map JavaDoc<String JavaDoc, Object JavaDoc> options) throws Exception JavaDoc;
199     
200     /**
201      * @see #transform(ContentReader, ContentWriter, Map)
202      * @see #transformInternal(ContentReader, ContentWriter, Map)
203      */

204     public final void transform(ContentReader reader, ContentWriter writer) throws ContentIOException
205     {
206         transform(reader, writer, null);
207     }
208
209     /**
210      * Performs the following:
211      * <ul>
212      * <li>Times the transformation</li>
213      * <li>Ensures that the transformation is allowed</li>
214      * <li>Calls the subclass implementation of {@link #transformInternal(ContentReader, ContentWriter)}</li>
215      * <li>Transforms any exceptions generated</li>
216      * <li>Logs a successful transformation</li>
217      * </ul>
218      * Subclass need only be concerned with performing the transformation.
219      * <p>
220      * If the options provided are null, then an empty map will be created.
221      */

222     public final void transform(
223             ContentReader reader,
224             ContentWriter writer,
225             Map JavaDoc<String JavaDoc, Object JavaDoc> options) throws ContentIOException
226     {
227         // begin timing
228
long before = System.currentTimeMillis();
229         
230         // check the reliability
231
checkReliability(reader, writer);
232         
233         // check options map
234
if (options == null)
235         {
236             options = Collections.emptyMap();
237         }
238         
239         try
240         {
241             transformInternal(reader, writer, options);
242         }
243         catch (Throwable JavaDoc e)
244         {
245             // Make sure that this transformation gets set back i.t.o. time taken.
246
// This will ensure that transformers that compete for the same transformation
247
// will be prejudiced against transformers that tend to fail
248
recordTime(10000); // 10 seconds, i.e. rubbish
249

250             throw new ContentIOException("Content conversion failed: \n" +
251                     " reader: " + reader + "\n" +
252                     " writer: " + writer + "\n" +
253                     " options: " + options,
254                     e);
255         }
256         finally
257         {
258             // check that the reader and writer are both closed
259
if (!reader.isClosed())
260             {
261                 logger.error("Content reader not closed by transformer: \n" +
262                         " reader: " + reader + "\n" +
263                         " transformer: " + this);
264             }
265             if (!writer.isClosed())
266             {
267                 logger.error("Content writer not closed by transformer: \n" +
268                         " writer: " + writer + "\n" +
269                         " transformer: " + this);
270             }
271         }
272         
273         // record time
274
long after = System.currentTimeMillis();
275         recordTime(after - before);
276         
277         // done
278
if (logger.isDebugEnabled())
279         {
280             logger.debug("Completed transformation: \n" +
281                     " reader: " + reader + "\n" +
282                     " writer: " + writer + "\n" +
283                     " options: " + options + "\n" +
284                     " transformer: " + this);
285         }
286     }
287
288     /**
289      * @return Returns the calculated running average of the current transformations
290      */

291     public synchronized long getTransformationTime()
292     {
293         return (long) averageTime;
294     }
295
296     /**
297      * Records and updates the average transformation time for this transformer.
298      * <p>
299      * Subclasses should call this after every transformation in order to keep
300      * the running average of the transformation times up to date.
301      * <p>
302      * This method is thread-safe. The time spent in this method is negligible
303      * so the impact will be minor.
304      *
305      * @param transformationTime the time it took to perform the transformation.
306      * The value may be 0.
307      */

308     protected final synchronized void recordTime(long transformationTime)
309     {
310         if (count == Long.MAX_VALUE)
311         {
312             // we have reached the max count - reduce it by half
313
// the average fluctuation won't be extreme
314
count /= 2L;
315         }
316         // adjust the average
317
count++;
318         double diffTime = ((double) transformationTime) - averageTime;
319         averageTime += diffTime / (double) count;
320     }
321 }
322
Popular Tags