001/* 002 * Copyright 2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.nuxeo.ecm.platform.ui.web.component.file; 017 018import java.io.IOException; 019 020import javax.el.ELException; 021import javax.el.ExpressionFactory; 022import javax.el.MethodExpression; 023import javax.el.ValueExpression; 024import javax.faces.FacesException; 025import javax.faces.application.Application; 026import javax.faces.component.NamingContainer; 027import javax.faces.component.UICommand; 028import javax.faces.component.UIComponent; 029import javax.faces.component.UIOutput; 030import javax.faces.component.html.HtmlCommandLink; 031import javax.faces.context.FacesContext; 032import javax.faces.context.ResponseWriter; 033 034import org.nuxeo.ecm.core.api.Blob; 035import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeEntry; 036import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry; 037import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 038import org.nuxeo.runtime.api.Framework; 039 040/** 041 * UIOutput file. 042 * <p> 043 * Attribute named value is the file to be displayed. Its submitted value as well as filename are handled by sub 044 * components in facets. Rendering is handled here. 045 * <p> 046 * If convertAction and editOnlineAction method bindings are set, corresponding links are rendered. The 047 * editOnlineActionRendered is used to filter action visibility. 048 * 049 * @author <a href="mailto:[email protected]">Anahide Tchertchian</a> 050 */ 051public class UIOutputFile extends UIOutput implements NamingContainer { 052 053 public static final String COMPONENT_TYPE = UIOutputFile.class.getName(); 054 055 public static final String COMPONENT_FAMILY = "javax.faces.Output"; 056 057 private static final String DOWNLOAD_FACET_NAME = "download"; 058 059 private static final String CONVERT_PDF_FACET_NAME = "convertToPdf"; 060 061 private static final String EDITONLINE_FACET_NAME = "editOnline"; 062 063 private String filename; 064 065 private MethodExpression convertAction; 066 067 private MethodExpression editOnlineAction; 068 069 // to perform test on rights or service availability 070 private Boolean editOnlineActionRendered; 071 072 // to get values from parent component, useful when embedded within an 073 // UIInputFile component 074 private Boolean queryParent; 075 076 private String separator = " | "; 077 078 private String downloadLabel; 079 080 private Boolean iconRendered; 081 082 public UIOutputFile() { 083 FacesContext faces = FacesContext.getCurrentInstance(); 084 Application app = faces.getApplication(); 085 ComponentUtils.initiateSubComponent(this, DOWNLOAD_FACET_NAME, 086 app.createComponent(UIOutputFileCommandLink.COMPONENT_TYPE)); 087 ComponentUtils.initiateSubComponent(this, CONVERT_PDF_FACET_NAME, 088 app.createComponent(HtmlCommandLink.COMPONENT_TYPE)); 089 ComponentUtils.initiateSubComponent(this, EDITONLINE_FACET_NAME, 090 app.createComponent(HtmlCommandLink.COMPONENT_TYPE)); 091 } 092 093 // component will render itself 094 @Override 095 public String getRendererType() { 096 return null; 097 } 098 099 // getters and setters 100 101 @Override 102 public Object getValue() { 103 if (getQueryParent()) { 104 UIComponent parent = getParent(); 105 if (parent instanceof UIInputFile) { 106 UIInputFile inputFile = (UIInputFile) parent; 107 return inputFile.getCurrentBlob(); 108 } 109 } 110 return super.getValue(); 111 } 112 113 public String getFilename() { 114 if (getQueryParent()) { 115 UIComponent parent = getParent(); 116 if (parent instanceof UIInputFile) { 117 UIInputFile inputFile = (UIInputFile) parent; 118 return inputFile.getCurrentFilename(); 119 } 120 } 121 // default way to get it 122 if (filename != null) { 123 return filename; 124 } 125 ValueExpression ve = getValueExpression("filename"); 126 if (ve != null) { 127 try { 128 return (String) ve.getValue(getFacesContext().getELContext()); 129 } catch (ELException e) { 130 throw new FacesException(e); 131 } 132 } else { 133 return null; 134 } 135 } 136 137 public void setFilename(String filename) { 138 this.filename = filename; 139 } 140 141 public MethodExpression getConvertAction() { 142 return convertAction; 143 } 144 145 public void setConvertAction(MethodExpression convertToPdfAction) { 146 convertAction = convertToPdfAction; 147 } 148 149 public MethodExpression getEditOnlineAction() { 150 return editOnlineAction; 151 } 152 153 public void setEditOnlineAction(MethodExpression editOnlineAction) { 154 this.editOnlineAction = editOnlineAction; 155 } 156 157 public Boolean getEditOnlineActionRendered() { 158 if (editOnlineActionRendered != null) { 159 return editOnlineActionRendered; 160 } 161 ValueExpression ve = getValueExpression("editOnlineActionRendered"); 162 if (ve != null) { 163 try { 164 return !Boolean.FALSE.equals(ve.getValue(getFacesContext().getELContext())); 165 } catch (ELException e) { 166 throw new FacesException(e); 167 } 168 } else { 169 // default value 170 return false; 171 } 172 } 173 174 public void setEditOnlineActionRendered(Boolean editOnlineActionRendered) { 175 this.editOnlineActionRendered = editOnlineActionRendered; 176 } 177 178 public String getSeparator() { 179 if (separator != null) { 180 return separator; 181 } 182 ValueExpression ve = getValueExpression("separator"); 183 if (ve != null) { 184 try { 185 return (String) ve.getValue(getFacesContext().getELContext()); 186 } catch (ELException e) { 187 throw new FacesException(e); 188 } 189 } else { 190 return null; 191 } 192 } 193 194 public Boolean getQueryParent() { 195 if (queryParent != null) { 196 return queryParent; 197 } 198 ValueExpression ve = getValueExpression("queryParent"); 199 if (ve != null) { 200 try { 201 return !Boolean.FALSE.equals(ve.getValue(getFacesContext().getELContext())); 202 } catch (ELException e) { 203 throw new FacesException(e); 204 } 205 } else { 206 // default value 207 return false; 208 } 209 } 210 211 public void setQueryParent(Boolean queryParent) { 212 this.queryParent = queryParent; 213 } 214 215 public void setSeparator(String actionsSeparator) { 216 separator = actionsSeparator; 217 } 218 219 public String getDownloadLabel() { 220 if (downloadLabel != null) { 221 return downloadLabel; 222 } 223 ValueExpression ve = getValueExpression("downloadLabel"); 224 if (ve != null) { 225 try { 226 return (String) ve.getValue(getFacesContext().getELContext()); 227 } catch (ELException e) { 228 throw new FacesException(e); 229 } 230 } else { 231 return null; 232 } 233 } 234 235 public void setDownloadLabel(String downloadLabel) { 236 this.downloadLabel = downloadLabel; 237 } 238 239 public Boolean getIconRendered() { 240 if (iconRendered != null) { 241 return iconRendered; 242 } 243 ValueExpression ve = getValueExpression("iconRendered"); 244 if (ve != null) { 245 try { 246 return !Boolean.FALSE.equals(ve.getValue(getFacesContext().getELContext())); 247 } catch (ELException e) { 248 throw new FacesException(e); 249 } 250 } else { 251 // default value 252 return true; 253 } 254 } 255 256 public void setIconRendered(Boolean iconRendered) { 257 this.iconRendered = iconRendered; 258 } 259 260 // rendering methods 261 protected ValueExpression getBlobExpression(FacesContext context) { 262 if (getQueryParent()) { 263 UIComponent parent = getParent(); 264 if (parent instanceof UIInputFile) { 265 UIInputFile inputFile = (UIInputFile) parent; 266 ExpressionFactory ef = context.getApplication().getExpressionFactory(); 267 return ef.createValueExpression(inputFile.getCurrentBlob(), Blob.class); 268 } 269 } 270 // default get 271 Object local = getLocalValue(); 272 if (local != null) { 273 ExpressionFactory ef = context.getApplication().getExpressionFactory(); 274 return ef.createValueExpression(local, Blob.class); 275 } else { 276 return getValueExpression("value"); 277 } 278 } 279 280 protected ValueExpression getFileNameExpression(FacesContext context) { 281 if (getQueryParent()) { 282 UIComponent parent = getParent(); 283 if (parent instanceof UIInputFile) { 284 UIInputFile inputFile = (UIInputFile) parent; 285 ExpressionFactory ef = context.getApplication().getExpressionFactory(); 286 return ef.createValueExpression(inputFile.getCurrentFilename(), String.class); 287 } 288 } 289 if (filename != null) { 290 ExpressionFactory ef = context.getApplication().getExpressionFactory(); 291 return ef.createValueExpression(filename, String.class); 292 } else { 293 return getValueExpression("filename"); 294 } 295 } 296 297 protected String getDownloadLinkValue(FacesContext context, Blob blob, String filename) { 298 String linkValue = getDownloadLabel(); 299 if (linkValue == null) { 300 if (filename == null || filename.length() == 0) { 301 linkValue = ComponentUtils.translate(context, "label.outputFile.download"); 302 } else { 303 linkValue = filename; 304 } 305 } else { 306 // try to translate it 307 linkValue = ComponentUtils.translate(context, linkValue); 308 } 309 // XXX AT: LazyBlob always returns 0 310 // if (blob != null) { 311 // Long size = blob.getLength(); 312 // if (size != null) { 313 // DecimalFormatSymbols dfs = new DecimalFormatSymbols(); 314 // dfs.setDecimalSeparator('.'); 315 // DecimalFormat df = new DecimalFormat("########.0", dfs); 316 // String stringSize = df.format(size / 1024.); 317 // linkValue += " (" + stringSize + "Ko)"; 318 // } 319 // } 320 return linkValue; 321 } 322 323 // encode component with its sub components 324 @Override 325 public void encodeBegin(FacesContext context) throws IOException { 326 Object value = getValue(); 327 if (value != null && value instanceof Blob) { 328 UIComponent downloadFacet = getFacet(DOWNLOAD_FACET_NAME); 329 if (downloadFacet != null) { 330 Blob blob = (Blob) value; 331 String filenameSet = getFilename(); 332 UICommand downloadComp = (UICommand) downloadFacet; 333 // action expression will be set thanks to parent values 334 downloadComp.setValue(getDownloadLinkValue(context, blob, filenameSet)); 335 downloadComp.setImmediate(true); 336 ComponentUtils.copyLinkValues(this, downloadComp); 337 if (getIconRendered()) { 338 // encode icon within link 339 encodeFileIcon(context, blob); 340 } 341 // encode component 342 ComponentUtils.encodeComponent(context, downloadComp); 343 } 344 } 345 } 346 347 public void encodeFileIcon(FacesContext context, Blob blob) throws IOException { 348 String iconPath = ""; 349 MimetypeRegistry mimeService = Framework.getService(MimetypeRegistry.class); 350 MimetypeEntry mimeEntry = mimeService.getMimetypeEntryByMimeType(blob.getMimeType()); 351 if (mimeEntry != null) { 352 if (mimeEntry.getIconPath() != null) { 353 // FIXME: above Context should find it 354 iconPath = "/icons/" + mimeEntry.getIconPath(); 355 } 356 } 357 if (iconPath.length() > 0) { 358 ResponseWriter writer = context.getResponseWriter(); 359 writer.startElement("img", this); 360 String src = context.getApplication().getViewHandler().getResourceURL(context, iconPath); 361 writer.writeURIAttribute("src", context.getExternalContext().encodeResourceURL(src), null); 362 writer.writeAttribute("alt", blob.getMimeType(), null); 363 writer.endElement("img"); 364 writer.write(ComponentUtils.WHITE_SPACE_CHARACTER); 365 writer.flush(); 366 } 367 } 368 369 // state holder 370 371 @Override 372 public Object saveState(FacesContext context) { 373 Object[] values = new Object[6]; 374 values[0] = super.saveState(context); 375 values[1] = filename; 376 values[2] = convertAction; 377 values[3] = editOnlineAction; 378 values[4] = editOnlineActionRendered; 379 values[5] = queryParent; 380 return values; 381 } 382 383 @Override 384 public void restoreState(FacesContext context, Object state) { 385 Object[] values = (Object[]) state; 386 super.restoreState(context, values[0]); 387 filename = (String) values[1]; 388 convertAction = (MethodExpression) values[2]; 389 editOnlineAction = (MethodExpression) values[3]; 390 editOnlineActionRendered = (Boolean) values[4]; 391 queryParent = (Boolean) values[5]; 392 } 393 394}