View Javadoc

1   /*
2    Copyright (C) 2007 Grid Systems, S.A.
3   
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8   
9    This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13  
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
17  */
18  package com.gridsystems.nextgrid.api.pom.ref;
19  
20  import java.awt.Image;
21  import java.io.BufferedInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.Closeable;
24  import java.io.File;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStream;
30  import java.io.Reader;
31  import java.io.StringWriter;
32  import java.io.Writer;
33  import java.net.URL;
34  import java.nio.charset.Charset;
35  
36  import javax.activation.DataHandler;
37  import javax.activation.DataSource;
38  import javax.activation.FileDataSource;
39  import javax.activation.URLDataSource;
40  import javax.mail.internet.MimeMultipart;
41  import javax.mail.internet.MimePart;
42  import javax.mail.internet.MimePartDataSource;
43  import javax.mail.util.ByteArrayDataSource;
44  
45  import org.apache.axis.attachments.ImageDataSource;
46  import org.apache.axis.attachments.ManagedMemoryDataSource;
47  import org.apache.axis.attachments.MimeMultipartDataSource;
48  import org.apache.axis.attachments.OctetStream;
49  import org.apache.axis.attachments.OctetStreamDataSource;
50  
51  /**
52   * References a DataHandler instance.
53   *
54   * @author Rodrigo Ruiz
55   */
56  public class DataHandlerReference extends ReferenceSupport<DataHandler> {
57  
58    /**
59     * Serial Version UID.
60     */
61    private static final long serialVersionUID = 7188245805082272044L;
62  
63    /**
64     * Buffer size for file I/O.
65     */
66    private static final int BUF_SIZE = 4096;
67  
68    /**
69     * Classes this reference can be casted to.
70     */
71    private static final Class<?>[] CAST_TO = {
72      InputStream.class, File.class, DataHandler.class, DataSource.class,
73      byte[].class, char[].class, String.class
74    };
75  
76    /**
77     * Classes this reference can be casted from.
78     */
79    private static final Class<?>[] CAST_FROM = {
80      DataHandler.class, DataSource.class, File.class,
81      byte[].class, char[].class, CharSequence.class, URL.class,
82      OctetStream.class, Image.class, MimeMultipart.class, MimePart.class
83    };
84  
85    /**
86     * Managed Data Handler.
87     */
88    private DataHandler dh;
89  
90    /**
91     * Creates a new instance.
92     */
93    public DataHandlerReference() {
94    }
95  
96    /**
97     * Creates a new instance.
98     *
99     * @param dh Initial value
100    */
101   public DataHandlerReference(DataHandler dh) {
102     setValue(dh);
103   }
104 
105   /**
106    * {@inheritDoc}
107    */
108   public boolean canCastFrom(Class<?> c) {
109     for (Class<?> cc : CAST_FROM) {
110       if (c.isAssignableFrom(cc)) {
111         return true;
112       }
113     }
114     return false;
115   }
116 
117   /**
118    * {@inheritDoc}
119    */
120   public boolean canCastTo(Class<?> c) {
121     for (Class<?> cc : CAST_TO) {
122       if (cc.isAssignableFrom(c)) {
123         return true;
124       }
125     }
126     return false;
127   }
128 
129   /**
130    * {@inheritDoc}
131    */
132   public Object castTo(Class<?> c) {
133     if (this.dh == null) {
134 
135       return null;
136 
137     } else if (DataHandler.class.isAssignableFrom(c)) {
138 
139       return this.dh;
140 
141     } else if (DataSource.class.isAssignableFrom(c)) {
142 
143       return this.dh.getDataSource();
144 
145     } else if (File.class.isAssignableFrom(c)) {
146 
147       DataSource ds = dh.getDataSource();
148       if (ds instanceof FileDataSource) {
149         return ((FileDataSource)ds).getFile();
150       } else if (ds instanceof ManagedMemoryDataSource) {
151         return ((ManagedMemoryDataSource)ds).getDiskCacheFile();
152       } else {
153         try {
154           File f = File.createTempFile("attachment", ".bin");
155           copy(ds.getInputStream(), new FileOutputStream(f));
156           return f;
157         } catch (IOException e) {
158           throw new RuntimeException("Error writing datahandler to file", e);
159         }
160       }
161     } else if (byte[].class.isAssignableFrom(c)) {
162       try {
163         InputStream is = new BufferedInputStream(dh.getInputStream());
164         ByteArrayOutputStream os = new ByteArrayOutputStream();
165         copy(is, os);
166         return os.toByteArray();
167       } catch (IOException e) {
168         throw new RuntimeException("Error reading datahandler", e);
169       }
170 
171     } else if (char[].class.isAssignableFrom(c)) {
172 
173       String s = (String)castTo(String.class);
174       return s.toCharArray();
175 
176     } else if (String.class.isAssignableFrom(c)) {
177 
178       try {
179         Charset cs = getCharset();
180         InputStreamReader reader = new InputStreamReader(dh.getInputStream(), cs);
181         StringWriter writer = new StringWriter();
182         copy(reader, writer);
183         return writer.getBuffer().toString();
184       } catch (IOException e) {
185         throw new RuntimeException("Error reading datahandler", e);
186       }
187 
188     } else {
189       throw new ClassCastException("Could not cast reference value to " + c);
190     }
191   }
192 
193   /**
194    * {@inheritDoc}
195    */
196   public DataHandler getValue() {
197     return this.dh;
198   }
199 
200   /**
201    * {@inheritDoc}
202    */
203   public Class<DataHandler> getValueType() {
204     return DataHandler.class;
205   }
206 
207   /**
208    * {@inheritDoc}
209    */
210   public void setValue(Object obj) {
211     if (obj == null) {
212       this.dh = null;
213     } else if (obj instanceof DataHandler) {
214       this.dh = (DataHandler)obj;
215     } else if (obj instanceof DataSource) {
216       this.dh = new DataHandler((DataSource)obj);
217     } else if (obj instanceof File) {
218       this.dh = new DataHandler(new FileDataSource((File)obj));
219     } else if (obj instanceof byte[]) {
220       setValue((byte[])obj, "application/octet-stream");
221     } else if (obj instanceof char[]) {
222       setValue("data", new String((char[])obj));
223     } else if (obj instanceof String) {
224       setValue("data", obj.toString());
225     } else if (obj instanceof OctetStream) {
226       setValue("data", (OctetStream)obj);
227     } else if (obj instanceof Image) {
228       setValue("data", (Image)obj);
229     } else if (obj instanceof MimeMultipart) {
230       setValue("data", (MimeMultipart)obj);
231     } else if (obj instanceof MimePart) {
232       this.dh = new DataHandler(new MimePartDataSource((MimePart)obj));
233     } else if (obj instanceof URL) {
234       this.dh = new DataHandler(new URLDataSource((URL)obj));
235     }
236     this.setAvailable(this.dh != null);
237   }
238 
239   /**
240    * Sets the value of this reference.
241    *
242    * @param bytes        An array of bytes containing the data
243    * @param contentType  The MIME content type
244    */
245   public void setValue(byte[] bytes, String contentType) {
246     this.dh = new DataHandler(new ByteArrayDataSource(bytes, contentType));
247     this.setAvailable(this.dh != null);
248   }
249 
250   /**
251    * Sets the value of this reference.
252    *
253    * @param name A name for the created data-source
254    * @param s    Value contents
255    */
256   public void setValue(String name, String s) {
257     try {
258       URL url = new URL(s);
259       setValue(url);
260     } catch (Exception e) {
261       // Not a URL
262       File f = new File(s);
263       if (f.isFile()) {
264         setValue(f);
265       } else {
266         URL url = Thread.currentThread().getContextClassLoader().getResource(s);
267         if (url != null) {
268           setValue(url);
269         }
270       }
271 
272     }
273   }
274 
275   /**
276    * Sets the value of this reference.
277    *
278    * @param name   A name for the created data-source
279    * @param stream Value contents
280    */
281   public void setValue(String name, OctetStream stream) {
282     this.dh = new DataHandler(new OctetStreamDataSource(name, stream));
283     this.setAvailable(this.dh != null);
284   }
285 
286   /**
287    * Sets the value of this reference.
288    *
289    * @param name  A name for the created data-source
290    * @param image Value contents
291    */
292   public void setValue(String name, Image image) {
293     this.dh = new DataHandler(new ImageDataSource(name, image));
294     this.setAvailable(this.dh != null);
295   }
296 
297   /**
298    * Sets the value of this reference.
299    *
300    * @param name A name for the created data-source
301    * @param part Value contents
302    */
303   public void setValue(String name, MimeMultipart part) {
304     this.dh = new DataHandler(new MimeMultipartDataSource(name, part));
305     this.setAvailable(this.dh != null);
306   }
307 
308   /**
309    * Gets a {@link Charset} instance by parsing the data handler content-type.
310    *
311    * @return A {@link Charset} instance
312    */
313   private Charset getCharset() {
314     String contentType = dh.getContentType();
315     int pos = contentType.indexOf("=");
316     String encoding = (pos == -1) ? "UTF-8" : contentType.substring(pos + 1);
317     try {
318       return Charset.forName(encoding);
319     } catch (Exception e) {
320       return Charset.defaultCharset();
321     }
322   }
323 
324   /**
325    * Copies from an input stream to an output one.
326    *
327    * @param is The stream to read from
328    * @param os The stream to write to
329    * @throws IOException If an error occurs
330    */
331   private static void copy(InputStream is, OutputStream os) throws IOException {
332     try {
333       byte[] buf = new byte[BUF_SIZE];
334       int count = is.read(buf);
335       while (count != -1) {
336         os.write(buf, 0, count);
337         count = is.read(buf);
338       }
339       os.flush();
340     } finally {
341       close(is);
342       close(os);
343     }
344   }
345 
346   /**
347    * Copies the contents of a reader into a writer.
348    *
349    * @param reader The reader to read from
350    * @param writer The writer to write to
351    * @throws IOException If an error occurs
352    */
353   private static void copy(Reader reader, Writer writer) throws IOException {
354     try {
355       char[] buf = new char[BUF_SIZE];
356       int count = reader.read(buf);
357       while (count != -1) {
358         writer.write(buf, 0, count);
359         count = reader.read(buf);
360       }
361       writer.flush();
362     } finally {
363       close(reader);
364       close(writer);
365     }
366   }
367 
368   /**
369    * Closes a closeable instance ignoring any exception.
370    *
371    * @param c The instance to close
372    */
373   private static void close(Closeable c) {
374     try {
375       c.close();
376     } catch (IOException e) {
377       // Ignore this exception
378     }
379   }
380 }