org.richfaces.resource.MediaOutputResource Maven / Gradle / Ivy
/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library 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.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.resource;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.component.StateHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import org.richfaces.component.AbstractMediaOutput;
import com.google.common.base.Strings;
/**
* @author Nick Belaevski
* @since 4.0
*/
@DynamicResource
public class MediaOutputResource extends AbstractUserResource implements StateHolder, CacheableResource {
private String contentType;
private boolean cacheable;
private MethodExpression contentProducer;
private ValueExpression expiresExpression;
private static final String PARENTHESES = "[^\\(]*";
/*
* TODO: add handling for expressions:
*
* 1. State saving 2. Evaluation
*/
private ValueExpression lastModifiedExpression;
private ValueExpression timeToLiveExpression;
private Object userData;
private String fileName;
public void encode(FacesContext facesContext) throws IOException {
OutputStream outStream = facesContext.getExternalContext().getResponseOutputStream();
String expr = contentProducer.getExpressionString();
if (!Pattern.matches(PARENTHESES, expr)) { // method expression must not be executed
throw new IllegalArgumentException("Expression \"" + expr + "\" contains parentheses.");
}
contentProducer.invoke(facesContext.getELContext(), new Object[] { outStream, userData });
}
public boolean isTransient() {
return false;
}
public void setTransient(boolean newTransientValue) {
throw new UnsupportedOperationException();
}
public Object saveState(FacesContext context) {
Object[] state = new Object[5];
// parent fields state saving
state[0] = isCacheable(context) ? Boolean.TRUE : Boolean.FALSE;
state[1] = getContentType();
state[2] = UIComponentBase.saveAttachedState(context, userData);
state[3] = UIComponentBase.saveAttachedState(context, contentProducer);
state[4] = fileName;
return state;
}
public void restoreState(FacesContext context, Object stateObject) {
Object[] state = (Object[]) stateObject;
setCacheable((Boolean) state[0]);
setContentType((String) state[1]);
userData = UIComponentBase.restoreAttachedState(context, state[2]);
contentProducer = (MethodExpression) UIComponentBase.restoreAttachedState(context, state[3]);
fileName = (String) state[4];
}
// TODO use ResourceComponent or exchange object as argument?
@PostConstructResource
public void initialize() {
AbstractMediaOutput uiMediaOutput = (AbstractMediaOutput) UIComponent.getCurrentComponent(FacesContext
.getCurrentInstance());
this.setCacheable(uiMediaOutput.isCacheable());
this.setContentType(uiMediaOutput.getMimeType());
this.userData = uiMediaOutput.getValue();
this.contentProducer = uiMediaOutput.getCreateContent();
this.lastModifiedExpression = uiMediaOutput.getValueExpression("lastModfied");
this.expiresExpression = uiMediaOutput.getValueExpression("expires");
this.timeToLiveExpression = uiMediaOutput.getValueExpression("timeToLive");
this.fileName = uiMediaOutput.getFileName();
}
public boolean isCacheable(FacesContext context) {
return cacheable;
}
public void setCacheable(boolean cacheable) {
this.cacheable = cacheable;
}
public Date getExpires(FacesContext context) {
return null;
}
public int getTimeToLive(FacesContext context) {
return -1;
}
public String getEntityTag(FacesContext context) {
return null;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Override
public Map getResponseHeaders() {
Map headers = new HashMap(2);
if (!Strings.isNullOrEmpty(fileName)) {
headers.put("Content-Disposition", "inline; filename=\"" + fileName + "\"");
}
return headers;
}
}