Source for javax.activation.DataHandler

   1: /* DataHandler.java -- Handler for data available in multiple formats.
   2:    Copyright (C) 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.activation;
  39: 
  40: import java.awt.datatransfer.DataFlavor;
  41: import java.awt.datatransfer.Transferable;
  42: import java.awt.datatransfer.UnsupportedFlavorException;
  43: import java.io.InputStream;
  44: import java.io.IOException;
  45: import java.io.OutputStream;
  46: import java.io.PipedInputStream;
  47: import java.io.PipedOutputStream;
  48: import java.net.URL;
  49: 
  50: /**
  51:  * Handler for data available in multiple sources and formats.
  52:  *
  53:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  54:  * @version 1.1
  55:  */
  56: public class DataHandler
  57:   implements Transferable
  58: {
  59: 
  60:   private static final DataFlavor[] NO_FLAVORS = new DataFlavor[0];
  61:   private static DataContentHandlerFactory factory = null;
  62: 
  63:   private final DataSource dataSource;
  64:   private DataSource objDataSource;
  65:   private Object object;
  66:   private String objectMimeType;
  67:   private CommandMap currentCommandMap;
  68:   private DataFlavor[] transferFlavors = NO_FLAVORS;
  69:   private DataContentHandler dataContentHandler;
  70:   private DataContentHandler factoryDCH;
  71:   private DataContentHandlerFactory oldFactory;
  72:   private String shortType;
  73: 
  74:   /**
  75:    * Constructor in which the data is read from a data source.
  76:    * @param ds the data source
  77:    */
  78:   public DataHandler(DataSource ds)
  79:   {
  80:     dataSource = ds;
  81:     oldFactory = factory;
  82:   }
  83: 
  84:   /**
  85:    * Constructor using a reified object representation.
  86:    * @param obj the object representation of the data
  87:    * @param mimeType the MIME type of the object
  88:    */
  89:   public DataHandler(Object obj, String mimeType)
  90:   {
  91:     dataSource = null;
  92:     object = obj;
  93:     objectMimeType = mimeType;
  94:     oldFactory = factory;
  95:   }
  96: 
  97:   /**
  98:    * Constructor in which the data is read from a URL.
  99:    * @param url the URL
 100:    */
 101:   public DataHandler(URL url)
 102:   {
 103:     dataSource = new URLDataSource(url);
 104:     oldFactory = factory;
 105:   }
 106: 
 107:   /**
 108:    * Returns the data source from which data is read.
 109:    */
 110:   public DataSource getDataSource()
 111:   {
 112:     if (dataSource != null)
 113:       {
 114:         return dataSource;
 115:       }
 116:     if (objDataSource == null)
 117:       {
 118:         objDataSource = new DataHandlerDataSource(this);
 119:       }
 120:     return objDataSource;
 121:   }
 122: 
 123:   /**
 124:    * Returns the name of the data object if created with a DataSource.
 125:    */
 126:   public String getName()
 127:   {
 128:     if (dataSource != null)
 129:       {
 130:         return dataSource.getName();
 131:       }
 132:     return null;
 133:   }
 134: 
 135:   /**
 136:    * Returns the MIME type of the data (with parameters).
 137:    */
 138:   public String getContentType()
 139:   {
 140:     if (dataSource != null)
 141:       {
 142:         return dataSource.getContentType();
 143:       }
 144:     return objectMimeType;
 145:   }
 146: 
 147:   /**
 148:    * Returns an input stream from which the data can be read.
 149:    */
 150:   public InputStream getInputStream()
 151:     throws IOException
 152:   {
 153:     if (dataSource != null)
 154:       {
 155:         return dataSource.getInputStream();
 156:       }
 157:     DataContentHandler dch = getDataContentHandler();
 158:     if (dch == null)
 159:       {
 160:         throw new UnsupportedDataTypeException("no DCH for MIME type " +
 161:                                                getShortType());
 162:       }
 163:     if ((dch instanceof ObjectDataContentHandler) &&
 164:         ((ObjectDataContentHandler)dch).getDCH() == null)
 165:       {
 166:         throw new UnsupportedDataTypeException("no object DCH " +
 167:                                                "for MIME type " +
 168:                                                getShortType());
 169:       }
 170:     PipedOutputStream pos = new PipedOutputStream();
 171:     DataContentHandlerWriter dchw =
 172:       new DataContentHandlerWriter(dch, object, objectMimeType, pos);
 173:     Thread thread = new Thread(dchw, "DataHandler.getInputStream");
 174:     thread.start();
 175:     return new PipedInputStream(pos);
 176:   }
 177: 
 178:   static class DataContentHandlerWriter
 179:     implements Runnable
 180:   {
 181: 
 182:     DataContentHandler dch;
 183:     Object object;
 184:     String mimeType;
 185:     OutputStream out;
 186: 
 187:     DataContentHandlerWriter(DataContentHandler dch, Object object,
 188:                              String mimeType, OutputStream out)
 189:     {
 190:       this.dch = dch;
 191:       this.object = object;
 192:       this.mimeType = mimeType;
 193:       this.out = out;
 194:     }
 195: 
 196:     public void run()
 197:     {
 198:       try
 199:         {
 200:           dch.writeTo(object, mimeType, out);
 201:         }
 202:       catch(IOException e)
 203:         {
 204:         }
 205:       finally
 206:         {
 207:           try
 208:             {
 209:               out.close();
 210:             }
 211:           catch(IOException e)
 212:             {
 213:             }
 214:         }
 215:     }
 216:   }
 217: 
 218:   /**
 219:    * Writes the data as a byte stream.
 220:    * @param os the stream to write to
 221:    */
 222:   public void writeTo(OutputStream os)
 223:     throws IOException
 224:   {
 225:     if (dataSource != null)
 226:       {
 227:         InputStream in = dataSource.getInputStream();
 228:         byte[] buf = new byte[8192];
 229:         for (int len = in.read(buf); len != -1; len = in.read(buf))
 230:           {
 231:             os.write(buf, 0, len);
 232:           }
 233:         in.close();
 234:       }
 235:     else
 236:       {
 237:         DataContentHandler dch = getDataContentHandler();
 238:         dch.writeTo(object, objectMimeType, os);
 239:       }
 240:   }
 241: 
 242:   /**
 243:    * Returns an output stream that can be used to overwrite the underlying
 244:    * data, if the DataSource constructor was used.
 245:    */
 246:   public OutputStream getOutputStream()
 247:     throws IOException
 248:   {
 249:     if (dataSource != null)
 250:       {
 251:         return dataSource.getOutputStream();
 252:       }
 253:     return null;
 254:   }
 255: 
 256:   /**
 257:    * Returns the data flavors in which this data is available.
 258:    */
 259:   public synchronized DataFlavor[] getTransferDataFlavors()
 260:   {
 261:     if (factory != oldFactory || transferFlavors == NO_FLAVORS)
 262:       {
 263:         DataContentHandler dch = getDataContentHandler();
 264:         transferFlavors = dch.getTransferDataFlavors();
 265:       }
 266:     return transferFlavors;
 267:   }
 268: 
 269:   /**
 270:    * Indicates whether the specified data flavor is supported for this
 271:    * data.
 272:    */
 273:   public boolean isDataFlavorSupported(DataFlavor flavor)
 274:   {
 275:     DataFlavor[] flavors = getTransferDataFlavors();
 276:     for (int i = 0; i < flavors.length; i++)
 277:       {
 278:         if (flavors[i].equals(flavor))
 279:           {
 280:             return true;
 281:           }
 282:       }
 283:     return false;
 284:   }
 285: 
 286:   /**
 287:    * Returns an object representing the data to be transferred.
 288:    * @param flavor the requested data flavor
 289:    */
 290:   public Object getTransferData(DataFlavor flavor)
 291:     throws UnsupportedFlavorException, IOException
 292:   {
 293:     DataContentHandler dch = getDataContentHandler();
 294:     return dch.getTransferData(flavor, dataSource);
 295:   }
 296: 
 297:   /**
 298:    * Sets the command map to be used by this data handler.
 299:    * Setting to null uses the default command map.
 300:    * @param commandMap the command map to use
 301:    */
 302:   public synchronized void setCommandMap(CommandMap commandMap)
 303:   {
 304:     if (commandMap != currentCommandMap || commandMap == null)
 305:       {
 306:         transferFlavors = NO_FLAVORS;
 307:         dataContentHandler = null;
 308:         currentCommandMap = commandMap;
 309:       }
 310:   }
 311: 
 312:   /**
 313:    * Returns the preferred commands for this type of data.
 314:    */
 315:   public CommandInfo[] getPreferredCommands()
 316:   {
 317:     CommandMap commandMap = getCommandMap();
 318:     return commandMap.getPreferredCommands(getShortType());
 319:   }
 320: 
 321:   /**
 322:    * Returns the complete list of commands for this type of data.
 323:    */
 324:   public CommandInfo[] getAllCommands()
 325:   {
 326:     CommandMap commandMap = getCommandMap();
 327:     return commandMap.getAllCommands(getShortType());
 328:   }
 329: 
 330:   /**
 331:    * Returns the specified command.
 332:    * @param cmdName the command name
 333:    */
 334:   public CommandInfo getCommand(String cmdName)
 335:   {
 336:     CommandMap commandMap = getCommandMap();
 337:     return commandMap.getCommand(getShortType(), cmdName);
 338:   }
 339: 
 340:   /**
 341:    * Returns the data as a reified object.
 342:    */
 343:   public Object getContent()
 344:     throws IOException
 345:   {
 346:     DataContentHandler dch = getDataContentHandler();
 347:     return dch.getContent(getDataSource());
 348:   }
 349: 
 350:   /**
 351:    * Returns the instantiated bean using the specified command.
 352:    * @param cmdInfo the command to instantiate the bean with
 353:    */
 354:   public Object getBean(CommandInfo cmdInfo)
 355:   {
 356:     try
 357:       {
 358:         return cmdInfo.getCommandObject(this, getClass().getClassLoader());
 359:       }
 360:     catch (IOException e)
 361:       {
 362:         e.printStackTrace(System.err);
 363:         return null;
 364:       }
 365:     catch (ClassNotFoundException e)
 366:       {
 367:         e.printStackTrace(System.err);
 368:         return null;
 369:       }
 370:   }
 371: 
 372:   /**
 373:    * Sets the data content handler factory.
 374:    * If the factory has already been set, throws an Error.
 375:    * @param newFactory the factory to set
 376:    */
 377:   public static synchronized void
 378:     setDataContentHandlerFactory(DataContentHandlerFactory newFactory)
 379:   {
 380:     if (factory != null)
 381:       {
 382:         throw new Error("DataContentHandlerFactory already defined");
 383:       }
 384:     SecurityManager security = System.getSecurityManager();
 385:     if (security != null)
 386:       {
 387:         try
 388:           {
 389:             security.checkSetFactory();
 390:           }
 391:         catch (SecurityException e)
 392:           {
 393:             if (newFactory != null && DataHandler.class.getClassLoader()
 394:                 != newFactory.getClass().getClassLoader())
 395:               {
 396:                 throw e;
 397:               }
 398:           }
 399:       }
 400:     factory = newFactory;
 401:   }
 402: 
 403:   /*
 404:    * Returns just the base part of the data's content-type, with no
 405:    * parameters.
 406:    */
 407:   private synchronized String getShortType()
 408:   {
 409:     if (shortType == null)
 410:       {
 411:         String contentType = getContentType();
 412:         try
 413:           {
 414:             MimeType mimeType = new MimeType(contentType);
 415:             shortType = mimeType.getBaseType();
 416:           }
 417:         catch (MimeTypeParseException e)
 418:           {
 419:             shortType = contentType;
 420:           }
 421:       }
 422:     return shortType;
 423:   }
 424: 
 425:   /*
 426:    * Returns the command map for this handler.
 427:    */
 428:   private synchronized CommandMap getCommandMap()
 429:   {
 430:     if (currentCommandMap != null)
 431:       {
 432:         return currentCommandMap;
 433:       }
 434:     return CommandMap.getDefaultCommandMap();
 435:   }
 436: 
 437:   /*
 438:    * Returns the DCH for this handler.
 439:    */
 440:   private synchronized DataContentHandler getDataContentHandler()
 441:   {
 442:     if (factory != oldFactory)
 443:       {
 444:         oldFactory = factory;
 445:         factoryDCH = null;
 446:         dataContentHandler = null;
 447:         transferFlavors = NO_FLAVORS;
 448:       }
 449:     if (dataContentHandler != null)
 450:       {
 451:         return dataContentHandler;
 452:       }
 453:     String mimeType = getShortType();
 454:     if (factoryDCH == null && factory != null)
 455:       {
 456:         factoryDCH = factory.createDataContentHandler(mimeType);
 457:       }
 458:     if (factoryDCH != null)
 459:       {
 460:         dataContentHandler = factoryDCH;
 461:       }
 462:     if (dataContentHandler == null)
 463:       {
 464:         CommandMap commandMap = getCommandMap();
 465:         dataContentHandler = commandMap.createDataContentHandler(mimeType);
 466:       }
 467:     if (dataSource != null)
 468:       {
 469:         dataContentHandler =
 470:           new DataSourceDataContentHandler(dataContentHandler, dataSource);
 471:       }
 472:     else
 473:       {
 474:         dataContentHandler =
 475:           new ObjectDataContentHandler(dataContentHandler, object,
 476:                                        objectMimeType);
 477:       }
 478:     return dataContentHandler;
 479:   }
 480: 
 481: }