/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright 2005 - 2009 Pentaho Corporation. All rights reserved.
*
*
* @created Jul 11, 2005
* @author James Dixon
*
*/
package org.pentaho.platform.web.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.engine.IContentOutputHandler;
import org.pentaho.platform.api.engine.IMimeTypeListener;
import org.pentaho.platform.api.engine.IOutputDef;
import org.pentaho.platform.api.engine.IOutputHandler;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.IRuntimeContext;
import org.pentaho.platform.api.repository.IContentItem;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.web.http.messages.Messages;
public class HttpOutputHandler implements IOutputHandler, IMimeTypeListener {
private static final Log logger = LogFactory.getLog(HttpOutputHandler.class);
private HttpServletResponse response;
protected IContentItem outputContent;
private IContentItem feedbackContent;
boolean allowFeedback;
@Deprecated
private boolean contentGenerated;
private IPentahoSession session;
private IMimeTypeListener mimeTypeListener;
protected IRuntimeContext runtimeContext;
private int outputType = IOutputHandler.OUTPUT_TYPE_DEFAULT;
private OutputStream destinationOutputStream;
private boolean responseExpected;
public HttpOutputHandler(final HttpServletResponse response, final OutputStream outputStream, final boolean allowFeedback) {
this.response = response;
destinationOutputStream = outputStream;
outputContent = new HttpContentItem(destinationOutputStream, this);
((HttpContentItem) outputContent).setMimeTypeListener(this);
feedbackContent = new HttpContentItem(destinationOutputStream, this);
this.allowFeedback = allowFeedback;
contentGenerated = false;
}
public void setSession(final IPentahoSession session) {
this.session = session;
}
public IPentahoSession getSession() {
return session;
}
public void setOutputPreference(final int outputType) {
this.outputType = outputType;
}
public int getOutputPreference() {
return outputType;
}
public void setMimeType(final String mimeType) {
if (mimeTypeListener != null) {
mimeTypeListener.setMimeType(mimeType);
}
response.setContentType(mimeType);
}
public void setName( String name ) {
if (mimeTypeListener != null) {
mimeTypeListener.setName(name);
}
}
@Deprecated
public boolean contentDone() {
return contentGenerated;
}
public boolean allowFeedback() {
return allowFeedback;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.core.solution.IOutputHandler#getOutputDefs()
*/
public Map getOutputDefs() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.core.solution.IOutputHandler#getOutputDef(java.lang.String)
*/
public IOutputDef getOutputDef(final String name) {
return null;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.core.solution.IOutputHandler#getFeedbackStream()
*/
public IContentItem getFeedbackContentItem() {
if (allowFeedback) {
// assume that content is generated becuase of this
contentGenerated = true;
/*
* if someone is requesting a feedbackContentItem, we can assume they tend to write feedback
* back to the client, so we set the flag here
*/
responseExpected = true;
return feedbackContent;
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.core.solution.IOutputHandler#getContentStream()
*/
public IContentItem getOutputContentItem(final String objectName, final String contentName, final String solution, final String instanceId,
final String mimeType) {
if (objectName.equals(IOutputHandler.RESPONSE) && contentName.equals(IOutputHandler.CONTENT)) {
// assume that content is generated becuase of this
// change the content type if necessary
if(mimeType != null) {
outputContent.setMimeType(mimeType);
}
contentGenerated = true;
/*
* if someone is requesting an outputContentItem, they are intending to write to the response
* output stream.
*/
responseExpected = true;
return outputContent;
} else {
IContentOutputHandler output = null;
// this code allows us to stay backwards compatible
if ((contentName != null) && (contentName.indexOf(":") == -1)) { //$NON-NLS-1$
output = PentahoSystem.getOutputDestinationFromContentRef(objectName + ":" + contentName, session); //$NON-NLS-1$
} else {
output = PentahoSystem.getOutputDestinationFromContentRef(contentName, session);
if (output == null) {
output = PentahoSystem.getOutputDestinationFromContentRef(objectName + ":" + contentName, session); //$NON-NLS-1$
}
}
if (output != null) {
output.setInstanceId(instanceId);
output.setMimeType(mimeType);
output.setSolutionName(solution);
return output.getFileOutputContentItem();
}
}
return null;
}
public IContentItem getOutputContentItem(final String objectName, final String contentName, final String title, final String url,
final String solution, final String instanceId, final String mimeType) {
return getOutputContentItem(objectName, contentName, solution, instanceId, mimeType);
}
public void setContentItem(final IContentItem content, final String objectName, final String contentName) {
if (objectName.equals(IOutputHandler.RESPONSE) && contentName.equals(IOutputHandler.CONTENT)) {
setMimeType(content.getMimeType());
}
}
public void setOutput(final String name, final Object value) {
if (value == null) {
HttpOutputHandler.logger.warn(Messages.getInstance().getString("HttpOutputHandler.WARN_0001_VALUE_IS_NULL")); //$NON-NLS-1$
return;
}
/*
* if setOutput is called, it means someone intends to write some data to the response stream,
* which they may not have gotten a handle to earlier through getOutputContentItem*. So we need to set the flag here.
*/
responseExpected = true;
if ("redirect".equalsIgnoreCase(name)) { //$NON-NLS-1$
try {
response.sendRedirect(value.toString());
} catch (IOException ioe) {
HttpOutputHandler.logger.error(Messages.getInstance().getString("HttpOutputHandler.ERROR_0001_REDIRECT_FAILED",value.toString()), ioe); //$NON-NLS-1$
}
} else if ("header".equalsIgnoreCase(name)) { //$NON-NLS-1$
try {
if (value instanceof Map) {
for (Iterator it = ((Map) value).entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
response.addHeader(entry.getKey().toString(), entry.getValue().toString());
}
} else {
String strVal = value.toString();
int i = strVal.indexOf('=');
String headerName = strVal.substring(0, i);
String headerValue = strVal.substring(i + 1);
response.addHeader(headerName, headerValue);
}
} catch (IndexOutOfBoundsException e) {
HttpOutputHandler.logger.error(e.getLocalizedMessage());
}
} else if (IOutputHandler.CONTENT.equalsIgnoreCase(name)) {
try {
if (value instanceof IContentItem) {
IContentItem content = (IContentItem) value;
// See if we should process the input stream. If it's from
// the content repository, then there's an input stream.
// SimpleContentItem and HttpContentItem both return null from
// getInputStream().
InputStream inStr = content.getInputStream();
if (inStr != null) {
if ((response.getContentType() == null)
|| (!response.getContentType().equalsIgnoreCase(content.getMimeType()))) {
// response.setContentType( content.getMimeType() );
setMimeType(content.getMimeType());
}
try {
//Bad idea to write to the output stream directly. This prevents us from
//auditing writes. Use the managed destinationOutputStream instead.
//OutputStream outStr = response.getOutputStream();
int inCnt = 0;
byte[] buf = new byte[4096];
while (-1 != (inCnt = inStr.read(buf))) {
destinationOutputStream.write(buf, 0, inCnt);
}
} finally {
try {
inStr.close();
} catch (IOException ignored) {
}
}
contentGenerated = true;
}
} else {
if (response.getContentType() == null) {
setMimeType("text/html"); //$NON-NLS-1$
}
destinationOutputStream.write(value.toString().getBytes());
contentGenerated = true;
}
} catch (IOException ioe) {
HttpOutputHandler.logger.error(null, ioe);
}
}
}
public IMimeTypeListener getMimeTypeListener() {
return mimeTypeListener;
}
public void setMimeTypeListener(final IMimeTypeListener mimeTypeListener) {
this.mimeTypeListener = mimeTypeListener;
}
public HttpServletResponse getResponse() {
return response;
}
public void setResponse(final HttpServletResponse response) {
this.response = response;
}
public boolean isResponseExpected() {
return responseExpected;
}
public void setRuntimeContext(final IRuntimeContext runtimeContext) {
this.runtimeContext = runtimeContext;
}
public boolean isWritable() {
return false;
}
}