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