blob: d9bbd8c2ee898f2ae937c9c90b64e86b2b51135a [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation.
*
* Licensed 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 org.apache.jackrabbit.server.io;
import org.apache.log4j.Logger;
import org.apache.jackrabbit.webdav.io.OutputContext;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.DavResource;
import javax.jcr.Item;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Date;
import java.io.File;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileOutputStream;
/**
* <code>ExportContextImpl</code> implements an <code>ExportContext</code> that
* wraps around the specified OutputContext as it was passed to
* {@link DavResource#spool(OutputContext)}. If a stream is provided a temporary
* file is created, which is deleted as soon as {@link #informCompleted(boolean)}
* is called on this context. Note however, that the properties and the stream
* are written to the <code>OutputContext</code> but upon successful completion.
*
* @see #informCompleted(boolean)
*/
public class ExportContextImpl extends AbstractExportContext {
private static Logger log = Logger.getLogger(ExportContextImpl.class);
private final Map properties = new HashMap();
private final OutputContext outputCtx;
private File outFile;
private OutputStream outStream;
public ExportContextImpl(Item exportRoot, OutputContext outputCtx) throws IOException {
super(exportRoot, (outputCtx != null) ? outputCtx.hasStream() : false, null);
this.outputCtx = outputCtx;
if (hasStream()) {
// we need a tmp file, since the export could fail
outFile = File.createTempFile("__exportcontext", "tmp");
}
}
/**
* Returns a new <code>OutputStream</code> to the temporary file or
* <code>null</code> if this context provides no stream.
*
* @see ExportContext#getOutputStream()
* @see #informCompleted(boolean)
*/
public OutputStream getOutputStream() {
checkCompleted();
if (hasStream()) {
try {
// clean up the stream retrieved by the preceeding handler, that
// did not behave properly and failed to export although initially
// willing to handle the export.
if (outStream != null) {
outStream.close();
}
outStream = new FileOutputStream(outFile);
return outStream;
} catch (IOException e) {
// unexpected error... ignore and return null
}
}
return null;
}
/**
* @see ExportContext#setContentLanguage(String)
*/
public void setContentLanguage(String contentLanguage) {
properties.put(DavConstants.HEADER_CONTENT_LANGUAGE, contentLanguage);
}
/**
* @see ExportContext#setContentLength(long)
*/
public void setContentLength(long contentLength) {
properties.put(DavConstants.HEADER_CONTENT_LENGTH, contentLength + "");
}
/**
* @see ExportContext#setContentType(String,String)
*/
public void setContentType(String mimeType, String encoding) {
properties.put(DavConstants.HEADER_CONTENT_TYPE, IOUtil.buildContentType(mimeType, encoding));
}
/**
* Does nothing since the wrapped output context does not understand
* creation time
*
* @param creationTime
* @see ExportContext#setCreationTime(long)
*/
public void setCreationTime(long creationTime) {
// ignore since output-ctx does not understand creation time
}
/**
* @see ExportContext#setModificationTime(long)
*/
public void setModificationTime(long modificationTime) {
if (modificationTime <= IOUtil.UNDEFINED_TIME) {
modificationTime = new Date().getTime();
}
String lastMod = IOUtil.getLastModified(modificationTime);
properties.put(DavConstants.HEADER_LAST_MODIFIED, lastMod);
}
/**
* @see ExportContext#setETag(String)
*/
public void setETag(String etag) {
properties.put(DavConstants.HEADER_ETAG, etag);
}
/**
* @see ExportContext#setProperty(Object, Object)
*/
public void setProperty(Object propertyName, Object propertyValue) {
properties.put(propertyName, propertyValue);
}
/**
* If success is true, the properties set before an the output stream are
* written to the wrapped <code>OutputContext</code>.
*
* @param success
* @see ExportContext#informCompleted(boolean)
*/
public void informCompleted(boolean success) {
checkCompleted();
completed = true;
// make sure the outputStream gets closed (and don't assume the handlers
// took care of this.
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
// ignore
}
}
if (success) {
// write properties and data to the output-context
if (outputCtx != null) {
boolean hasContentLength = false;
Iterator it = properties.keySet().iterator();
while (it.hasNext()) {
String name = it.next().toString();
String value = properties.get(name).toString();
outputCtx.setProperty(name, value);
// check for content-length
hasContentLength = DavConstants.HEADER_CONTENT_LENGTH.equals(name);
}
if (outputCtx.hasStream() && outFile != null) {
OutputStream out = outputCtx.getOutputStream();
try {
// make sure the content-length is set
if (!hasContentLength) {
outputCtx.setContentLength(outFile.length());
}
FileInputStream in = new FileInputStream(outFile);
IOUtil.spool(in, out);
} catch (IOException e) {
log.error(e);
}
}
}
}
if (outFile != null) {
outFile.delete();
}
}
}