blob: b4b4bcf60ddf8b737786de46689ba79ec41b7dca [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package javax.activation;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.URL;
public class DataHandler implements Transferable {
private final DataSource ds;
private final DataFlavor flavor;
private CommandMap commandMap;
private DataContentHandler dch;
public DataHandler(DataSource ds) {
this.ds = ds;
this.flavor = new ActivationDataFlavor(ds.getContentType(), null);
}
public DataHandler(Object data, String type) {
this.ds = new ObjectDataSource(data, type);
this.flavor = new ActivationDataFlavor(data.getClass(), null);
}
public DataHandler(URL url) {
this.ds = new URLDataSource(url);
this.flavor = new ActivationDataFlavor(ds.getContentType(), null);
}
public DataSource getDataSource() {
return ds;
}
public String getName() {
return ds.getName();
}
public String getContentType() {
return ds.getContentType();
}
public InputStream getInputStream() throws IOException {
return ds.getInputStream();
}
public void writeTo(OutputStream os) throws IOException {
if (ds instanceof ObjectDataSource) {
ObjectDataSource ods = (ObjectDataSource) ds;
DataContentHandler dch = getDataContentHandler();
if (dch == null) {
throw new UnsupportedDataTypeException(ods.mimeType);
}
dch.writeTo(ods.data, ods.mimeType, os);
} else {
byte[] buffer = new byte[1024];
InputStream is = getInputStream();
try {
int count;
while ((count = is.read(buffer)) != -1) {
os.write(buffer, 0, count);
}
} finally {
is.close();
}
}
}
public OutputStream getOutputStream() throws IOException {
return ds.getOutputStream();
}
public synchronized DataFlavor[] getTransferDataFlavors() {
return getDataContentHandler().getTransferDataFlavors();
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
DataFlavor[] flavors = getTransferDataFlavors();
for (int i = 0; i < flavors.length; i++) {
DataFlavor dataFlavor = flavors[i];
if (dataFlavor.equals(flavor)) {
return true;
}
}
return false;
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
DataContentHandler dch = getDataContentHandler();
if (dch != null) {
return dch.getTransferData(flavor, ds);
} else if (this.flavor.match(flavor)) {
if (ds instanceof ObjectDataSource) {
return ((ObjectDataSource) ds).data;
} else {
return ds.getInputStream();
}
} else {
throw new UnsupportedFlavorException(flavor);
}
}
public CommandInfo[] getPreferredCommands() {
return getCommandMap().getPreferredCommands(ds.getContentType());
}
public CommandInfo[] getAllCommands() {
return getCommandMap().getAllCommands(ds.getContentType());
}
public CommandInfo getCommand(String cmdName) {
return getCommandMap().getCommand(ds.getContentType(), cmdName);
}
public Object getContent() throws IOException {
if (ds instanceof ObjectDataSource) {
return ((ObjectDataSource) ds).data;
} else {
DataContentHandler dch = getDataContentHandler();
if (dch != null) {
return dch.getContent(ds);
} else {
return ds.getInputStream();
}
}
}
public Object getBean(CommandInfo cmdinfo) {
try {
return cmdinfo.getCommandObject(this, this.getClass().getClassLoader());
} catch (IOException e) {
return null;
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* A local implementation of DataSouce used to wrap an Object and mime-type.
*/
private class ObjectDataSource implements DataSource {
private final Object data;
private final String mimeType;
public ObjectDataSource(Object data, String mimeType) {
this.data = data;
this.mimeType = mimeType;
}
public String getName() {
return null;
}
public String getContentType() {
return mimeType;
}
public InputStream getInputStream() throws IOException {
final DataContentHandler dch = getDataContentHandler();
if (dch == null) {
throw new UnsupportedDataTypeException(mimeType);
}
final PipedInputStream is = new PipedInputStream();
final PipedOutputStream os = new PipedOutputStream(is);
Thread thread = new Thread("DataHandler Pipe Pump") {
public void run() {
try {
try {
dch.writeTo(data, mimeType, os);
} finally {
os.close();
}
} catch (IOException e) {
// ignore, per spec - doh!
}
}
};
thread.start();
return is;
}
public OutputStream getOutputStream() throws IOException {
return null;
}
}
public synchronized void setCommandMap(CommandMap commandMap) {
this.commandMap = commandMap;
this.dch = null;
}
private synchronized CommandMap getCommandMap() {
return commandMap != null ? commandMap : CommandMap.getDefaultCommandMap();
}
/**
* Search for a DataContentHandler for our mime type.
* The search is performed by first checking if a global factory has been set using
* {@link #setDataContentHandlerFactory(DataContentHandlerFactory)};
* if found then it is called to attempt to create a handler.
* If this attempt fails, we then call the command map set using {@link #setCommandMap(CommandMap)}
* (or if that has not been set, the default map returned by {@link CommandMap#getDefaultCommandMap()})
* to create the handler.
*
* The resulting handler is cached until the global factory is changed.
*
* @return
*/
private synchronized DataContentHandler getDataContentHandler() {
DataContentHandlerFactory localFactory;
synchronized (DataHandler.class) {
if (factory != originalFactory) {
// setDCHF was called - clear our cached copy of the DCH and DCHF
dch = null;
originalFactory = factory;
}
localFactory = originalFactory;
}
if (dch == null) {
// get the main mime-type portion of the content.
String mimeType = getMimeType(ds.getContentType());
if (localFactory != null) {
dch = localFactory.createDataContentHandler(mimeType);
}
if (dch == null) {
dch = getCommandMap().createDataContentHandler(mimeType);
}
}
return dch;
}
/**
* Retrieve the base MIME type from a content type. This parses
* the type into its base components, stripping off any parameter
* information.
*
* @param contentType
* The content type string.
*
* @return The MIME type identifier portion of the content type.
*/
private String getMimeType(String contentType) {
try {
MimeType mimeType = new MimeType(contentType);
return mimeType.getBaseType();
} catch (MimeTypeParseException e) {
}
return contentType;
}
/**
* This is used to check if the DataContentHandlerFactory has been changed.
* This is not specified behaviour but this check is required to make this work like the RI.
*/
private DataContentHandlerFactory originalFactory;
{
synchronized (DataHandler.class) {
originalFactory = factory;
}
}
private static DataContentHandlerFactory factory;
/**
* Set the DataContentHandlerFactory to use.
* If this method has already been called then an Error is raised.
*
* @param newFactory the new factory
* @throws SecurityException if the caller does not have "SetFactory" RuntimePermission
*/
public static synchronized void setDataContentHandlerFactory(DataContentHandlerFactory newFactory) {
if (factory != null) {
throw new Error("javax.activation.DataHandler.setDataContentHandlerFactory has already been defined");
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkSetFactory();
}
factory = newFactory;
}
}