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