001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ 018 */ 019 020package org.nuxeo.ecm.platform.picture.web; 021 022import static org.jboss.seam.ScopeType.CONVERSATION; 023 024import java.io.BufferedOutputStream; 025import java.io.IOException; 026import java.io.Serializable; 027import java.util.ArrayList; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031import java.util.zip.ZipException; 032import java.util.zip.ZipOutputStream; 033 034import javax.faces.context.FacesContext; 035import javax.faces.model.SelectItem; 036import javax.servlet.http.HttpServletResponse; 037 038import org.apache.commons.logging.Log; 039import org.apache.commons.logging.LogFactory; 040import org.jboss.seam.annotations.Create; 041import org.jboss.seam.annotations.Destroy; 042import org.jboss.seam.annotations.In; 043import org.jboss.seam.annotations.Name; 044import org.jboss.seam.annotations.Observer; 045import org.jboss.seam.annotations.Scope; 046import org.jboss.seam.annotations.intercept.BypassInterceptors; 047import org.jboss.seam.core.Events; 048import org.nuxeo.common.utils.ZipUtils; 049import org.nuxeo.ecm.core.api.Blob; 050import org.nuxeo.ecm.core.api.CoreSession; 051import org.nuxeo.ecm.core.api.DocumentModel; 052import org.nuxeo.ecm.core.api.PathRef; 053import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 054import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService; 055import org.nuxeo.ecm.platform.picture.api.adapters.AbstractPictureAdapter; 056import org.nuxeo.ecm.platform.picture.api.adapters.PictureBlobHolder; 057import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 058import org.nuxeo.ecm.platform.ui.web.api.UserAction; 059import org.nuxeo.ecm.webapp.base.InputController; 060import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager; 061import org.nuxeo.ecm.webapp.helpers.EventNames; 062import org.nuxeo.runtime.api.Framework; 063 064/** 065 * Provide Picture Book related Actions. 066 * 067 * @author <a href="mailto:ldoguin@nuxeo.com">Laurent Doguin</a> 068 * @deprecated since 6.0. See NXP-15370. 069 */ 070@Name("pictureBookManager") 071@Scope(CONVERSATION) 072@Deprecated 073public class PictureBookManagerBean extends InputController implements PictureBookManager, Serializable { 074 075 private static final long serialVersionUID = 1L; 076 077 private static final Log log = LogFactory.getLog(PictureBookManagerBean.class); 078 079 @In(create = true) 080 protected CoreSession documentManager; 081 082 protected Integer maxsize; 083 084 protected ArrayList<Map<String, Object>> views; 085 086 protected String title; 087 088 protected String viewtitle; 089 090 protected String tag; 091 092 protected String description; 093 094 protected List<SelectItem> selectItems; 095 096 protected String[] selectedViews = { "OriginalJpeg" }; 097 098 @In(create = true) 099 protected transient NavigationContext navigationContext; 100 101 @In(create = true) 102 protected transient DocumentsListsManager documentsListsManager; 103 104 protected static final int BUFFER = 2048; 105 106 protected DocumentModel getCurrentDocument() { 107 return navigationContext.getCurrentDocument(); 108 } 109 110 @Override 111 @Create 112 public void initialize() { 113 log.debug("Initializing..."); 114 initViews(); 115 } 116 117 protected void initViews() { 118 // Sets the default views original, thumbnail and medium. 119 views = new ArrayList<Map<String, Object>>(); 120 Map<String, Object> map = new HashMap<String, Object>(); 121 map.put("title", "Medium"); 122 map.put("maxsize", AbstractPictureAdapter.MEDIUM_SIZE); 123 map.put("tag", "medium"); 124 map.put("description", "MediumSize Picture"); 125 views.add(map); 126 map = new HashMap<String, Object>(); 127 map.put("title", "Thumbnail"); 128 map.put("maxsize", AbstractPictureAdapter.THUMB_SIZE); 129 map.put("tag", "thumbnail"); 130 map.put("description", "ThumbnailSize Picture"); 131 views.add(map); 132 map = new HashMap<String, Object>(); 133 map.put("title", "OriginalJpeg"); 134 map.put("maxsize", null); 135 map.put("tag", "originalJpeg"); 136 map.put("description", "Original Picture in JPEG format"); 137 views.add(map); 138 } 139 140 @Destroy 141 @BypassInterceptors 142 public void destroy() { 143 title = null; 144 viewtitle = null; 145 maxsize = null; 146 tag = null; 147 description = null; 148 views = null; 149 log.debug("Destroy"); 150 } 151 152 @Override 153 public String createPictureBook() { 154 PathSegmentService pss = Framework.getService(PathSegmentService.class); 155 DocumentModel doc = navigationContext.getChangeableDocument(); 156 157 String parentPath; 158 if (getCurrentDocument() == null) { 159 // creating item at the root 160 parentPath = documentManager.getRootDocument().getPathAsString(); 161 } else { 162 parentPath = navigationContext.getCurrentDocument().getPathAsString(); 163 } 164 165 doc.setProperty("picturebook", "picturetemplates", views); 166 167 Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED, 168 documentManager.getDocument(new PathRef(parentPath))); 169 doc.setPathInfo(parentPath, pss.generatePathSegment(doc)); 170 doc = documentManager.createDocument(doc); 171 documentManager.saveDocument(doc); 172 documentManager.save(); 173 174 return navigationContext.getActionResult(doc, UserAction.AFTER_CREATE); 175 } 176 177 @Override 178 public void addView() { 179 Map<String, Object> map = new HashMap<String, Object>(); 180 map.put("title", viewtitle); 181 map.put("maxsize", maxsize); 182 map.put("tag", tag); 183 map.put("description", description); 184 views.add(map); 185 } 186 187 @Override 188 @Observer({ EventNames.DOCUMENT_SELECTION_CHANGED }) 189 @BypassInterceptors 190 public void reset() { 191 title = null; 192 maxsize = null; 193 viewtitle = null; 194 tag = null; 195 description = null; 196 selectItems = null; 197 selectedViews = new String[] { "Original" }; 198 initViews(); 199 } 200 201 @Override 202 public String downloadSelectedBook() throws IOException { 203 List<DocumentModel> list = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION); 204 return createZip(list); 205 } 206 207 @Override 208 public String downloadAll() throws IOException { 209 DocumentModel currentDoc = navigationContext.getCurrentDocument(); 210 if (currentDoc != null) { 211 List<DocumentModel> list = documentManager.getChildren(currentDoc.getRef()); 212 return createZip(list); 213 } 214 return null; 215 } 216 217 protected boolean isEmptyFolder(DocumentModel doc) { 218 List<DocumentModel> docList = documentManager.getChildren(doc.getRef()); 219 for (DocumentModel docChild : docList) { 220 BlobHolder bh = docChild.getAdapter(BlobHolder.class); 221 if (docChild.isFolder()) { 222 return isEmptyFolder(docChild); 223 } else if (bh != null) { 224 return false; 225 } 226 } 227 return true; 228 } 229 230 protected String formatFileName(String filename, String count) { 231 StringBuilder sb = new StringBuilder(); 232 CharSequence name = filename.subSequence(0, filename.lastIndexOf("")); 233 CharSequence extension = filename.subSequence(filename.lastIndexOf(""), filename.length()); 234 sb.append(name).append(count).append(extension); 235 return sb.toString(); 236 } 237 238 protected void addBlobHolderToZip(String path, ZipOutputStream out, byte[] data, PictureBlobHolder bh) 239 throws IOException { 240 List<Blob> blobs; 241 if (selectedViews != null) { 242 blobs = bh.getBlobs(selectedViews); 243 } else { 244 blobs = bh.getBlobs(); 245 } 246 for (Blob content : blobs) { 247 String fileName = content.getFilename(); 248 if (content != null) { 249 // Workaround to deal with duplicate file names. 250 int tryCount = 0; 251 while (true) { 252 try { 253 if (tryCount == 0) { 254 ZipUtils._zip(path + fileName, content.getStream(), out); 255 } else { 256 ZipUtils._zip(path + formatFileName(fileName, "(" + tryCount + ")"), content.getStream(), 257 out); 258 } 259 break; 260 } catch (ZipException e) { 261 tryCount++; 262 } 263 } 264 } 265 } 266 } 267 268 protected void addFolderToZip(String path, ZipOutputStream out, DocumentModel doc, byte[] data) 269 throws IOException { 270 271 String title = (String) doc.getProperty("dublincore", "title"); 272 List<DocumentModel> docList = documentManager.getChildren(doc.getRef()); 273 for (DocumentModel docChild : docList) { 274 275 // NXP-2334 : skip deleted docs 276 if (docChild.getCurrentLifeCycleState().equals("delete")) { 277 continue; 278 } 279 280 BlobHolder bh = docChild.getAdapter(BlobHolder.class); 281 if (docChild.isFolder() && !isEmptyFolder(docChild)) { 282 addFolderToZip(path + title + "/", out, docChild, data); 283 } else if (bh != null) { 284 addBlobHolderToZip(path + title + "/", out, data, (PictureBlobHolder) bh); 285 } 286 } 287 } 288 289 protected String createZip(List<DocumentModel> documents) throws IOException { 290 291 FacesContext context = FacesContext.getCurrentInstance(); 292 HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse(); 293 294 BufferedOutputStream buff = new BufferedOutputStream(response.getOutputStream()); 295 ZipOutputStream out = new ZipOutputStream(buff); 296 out.setMethod(ZipOutputStream.DEFLATED); 297 out.setLevel(9); 298 byte[] data = new byte[BUFFER]; 299 for (DocumentModel doc : documents) { 300 301 // first check if DM is attached to the core 302 if (doc.getSessionId() == null) { 303 // refetch the doc from the core 304 doc = documentManager.getDocument(doc.getRef()); 305 } 306 307 // NXP-2334 : skip deleted docs 308 if (doc.getCurrentLifeCycleState().equals("delete")) { 309 continue; 310 } 311 312 BlobHolder bh = doc.getAdapter(BlobHolder.class); 313 if (doc.isFolder() && !isEmptyFolder(doc)) { 314 addFolderToZip("", out, doc, data); 315 } else if (bh != null) { 316 addBlobHolderToZip("", out, data, (PictureBlobHolder) bh); 317 } 318 } 319 try { 320 out.close(); 321 } catch (ZipException e) { 322 // empty zip file, do nothing 323 setFacesMessage("label.clipboard.emptyDocuments"); 324 return null; 325 } 326 response.setHeader("Content-Disposition", "attachment; filename=\"" + "clipboard.zip" + "\";"); 327 response.setContentType("application/gzip"); 328 response.flushBuffer(); 329 context.responseComplete(); 330 return null; 331 } 332 333 protected void initSelectItems() { 334 DocumentModel doc = getCurrentDocument(); 335 List<Map<String, Object>> views = (List) doc.getProperty("picturebook", "picturetemplates"); 336 selectItems = new ArrayList<SelectItem>(views.size()); 337 String label; 338 SelectItem selectItem; 339 for (Map<String, Object> map : views) { 340 label = (String) map.get("title"); 341 selectItem = new SelectItem(label, label); 342 selectItems.add(selectItem); 343 } 344 } 345 346 @Override 347 public List<SelectItem> getSelectItems() { 348 if (selectItems == null) { 349 initSelectItems(); 350 return selectItems; 351 } else { 352 return selectItems; 353 } 354 } 355 356 @Override 357 public void setSelectItems(List<SelectItem> selectItems) { 358 this.selectItems = selectItems; 359 } 360 361 @Override 362 public String[] getSelectedViews() { 363 return selectedViews; 364 } 365 366 @Override 367 public void setSelectedViews(String[] selectedViews) { 368 this.selectedViews = selectedViews; 369 } 370 371 @Override 372 public Integer getMaxsize() { 373 return maxsize; 374 } 375 376 @Override 377 public void setMaxsize(Integer maxsize) { 378 this.maxsize = maxsize; 379 } 380 381 @Override 382 public String getTitle() { 383 return title; 384 } 385 386 @Override 387 public void setTitle(String title) { 388 this.title = title; 389 } 390 391 @Override 392 public String getTag() { 393 return tag; 394 } 395 396 @Override 397 public void setTag(String tag) { 398 this.tag = tag; 399 } 400 401 @Override 402 public String getDescription() { 403 return description; 404 } 405 406 @Override 407 public void setDescription(String description) { 408 this.description = description; 409 } 410 411 @Override 412 public String getViewtitle() { 413 return viewtitle; 414 } 415 416 @Override 417 public void setViewtitle(String viewtitle) { 418 this.viewtitle = viewtitle; 419 } 420 421 @Override 422 public ArrayList<Map<String, Object>> getViews() { 423 return views; 424 } 425 426 @Override 427 public void setViews(ArrayList<Map<String, Object>> views) { 428 this.views = views; 429 } 430 431}