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.IOException; 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.Map; 029 030import javax.faces.application.FacesMessage; 031import javax.faces.context.FacesContext; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.jboss.seam.annotations.Create; 036import org.jboss.seam.annotations.Destroy; 037import org.jboss.seam.annotations.In; 038import org.jboss.seam.annotations.Name; 039import org.jboss.seam.annotations.Observer; 040import org.jboss.seam.annotations.Scope; 041import org.jboss.seam.annotations.intercept.BypassInterceptors; 042import org.jboss.seam.annotations.remoting.WebRemote; 043import org.jboss.seam.annotations.web.RequestParameter; 044import org.jboss.seam.core.Events; 045import org.jboss.seam.faces.FacesMessages; 046import org.jboss.seam.international.StatusMessage; 047import org.nuxeo.ecm.core.api.Blob; 048import org.nuxeo.ecm.core.api.CoreSession; 049import org.nuxeo.ecm.core.api.DocumentLocation; 050import org.nuxeo.ecm.core.api.DocumentModel; 051import org.nuxeo.ecm.core.api.IdRef; 052import org.nuxeo.ecm.core.api.model.Property; 053import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService; 054import org.nuxeo.ecm.platform.commandline.executor.api.CommandAvailability; 055import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService; 056import org.nuxeo.ecm.platform.picture.api.adapters.PictureResourceAdapter; 057import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 058import org.nuxeo.ecm.platform.ui.web.api.UserAction; 059import org.nuxeo.ecm.platform.ui.web.rest.RestHelper; 060import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions; 061import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 062import org.nuxeo.ecm.platform.url.api.DocumentView; 063import org.nuxeo.ecm.platform.url.codec.DocumentFileCodec; 064import org.nuxeo.ecm.platform.util.RepositoryLocation; 065import org.nuxeo.ecm.webapp.helpers.EventNames; 066import org.nuxeo.ecm.webapp.helpers.ResourcesAccessor; 067import org.nuxeo.runtime.api.Framework; 068 069/** 070 * @author <a href="mailto:ldoguin@nuxeo.com">Laurent Doguin</a> 071 */ 072@Name("pictureManager") 073@Scope(CONVERSATION) 074public class PictureManagerBean implements PictureManager, Serializable { 075 076 private static final long serialVersionUID = 1L; 077 078 private static final Log log = LogFactory.getLog(PictureManagerBean.class); 079 080 protected static Boolean imageMagickAvailable; 081 082 @In(create = true, required = false) 083 protected transient CoreSession documentManager; 084 085 @RequestParameter 086 protected String fileFieldFullName; 087 088 @In(required = true, create = true) 089 protected transient NavigationContext navigationContext; 090 091 @In(create = true, required = false) 092 protected ResourcesAccessor resourcesAccessor; 093 094 protected String fileurlPicture; 095 096 protected String filename; 097 098 protected Blob fileContent; 099 100 protected Integer index; 101 102 protected String cropCoords; 103 104 protected ArrayList<Map<String, Object>> selectItems; 105 106 @Override 107 @Create 108 public void initialize() { 109 log.debug("Initializing..."); 110 index = 0; 111 } 112 113 protected DocumentModel getCurrentDocument() { 114 return navigationContext.getCurrentDocument(); 115 } 116 117 @Override 118 @SuppressWarnings("unchecked") 119 public String getFileurlPicture() { 120 ArrayList<Map<String, Object>> views = (ArrayList) getCurrentDocument().getProperty("picture", "views"); 121 return views.get(index).get("title") + ":content"; 122 } 123 124 @Override 125 public void setFileurlPicture(String fileurlPicture) { 126 this.fileurlPicture = fileurlPicture; 127 } 128 129 @SuppressWarnings({ "unchecked", "rawtypes" }) 130 protected void initSelectItems() { 131 selectItems = new ArrayList<Map<String, Object>>(); 132 DocumentModel doc = getCurrentDocument(); 133 ArrayList<Map<String, Object>> views = (ArrayList) doc.getProperty("picture", "views"); 134 for (int i = 0; i < views.size(); i++) { 135 Map<String, Object> map = new HashMap<String, Object>(); 136 map.put("title", views.get(i).get("title")); 137 map.put("idx", i); 138 selectItems.add(map); 139 } 140 } 141 142 @Override 143 public ArrayList getSelectItems() { 144 if (selectItems == null) { 145 initSelectItems(); 146 return selectItems; 147 } else { 148 return selectItems; 149 } 150 } 151 152 @Override 153 public void setSelectItems(ArrayList selectItems) { 154 this.selectItems = selectItems; 155 } 156 157 @Override 158 @Deprecated 159 @SuppressWarnings("unchecked") 160 public String addPicture() { 161 PathSegmentService pss = Framework.getService(PathSegmentService.class); 162 DocumentModel doc = navigationContext.getChangeableDocument(); 163 164 String parentPath; 165 if (getCurrentDocument() == null) { 166 // creating item at the root 167 parentPath = documentManager.getRootDocument().getPathAsString(); 168 } else { 169 parentPath = navigationContext.getCurrentDocument().getPathAsString(); 170 } 171 172 String title = (String) doc.getProperty("dublincore", "title"); 173 if (title == null) { 174 title = ""; 175 } 176 // set parent path and name for document model 177 doc.setPathInfo(parentPath, pss.generatePathSegment(doc)); 178 try { 179 DocumentModel parent = getCurrentDocument(); 180 ArrayList<Map<String, Object>> pictureConversions = null; 181 if (parent.getType().equals("PictureBook")) { 182 // Use PictureBook Properties 183 pictureConversions = (ArrayList<Map<String, Object>>) parent.getProperty("picturebook", 184 "picturetemplates"); 185 } 186 PictureResourceAdapter picture = doc.getAdapter(PictureResourceAdapter.class); 187 boolean status = picture.fillPictureViews(fileContent, filename, title, pictureConversions); 188 if (!status) { 189 documentManager.cancel(); 190 log.info("Picture type unsupported."); 191 FacesMessages.instance().add(StatusMessage.Severity.ERROR, 192 resourcesAccessor.getMessages().get("label.picture.upload.error")); 193 194 return navigationContext.getActionResult(navigationContext.getCurrentDocument(), UserAction.VIEW); 195 } else { 196 doc = documentManager.createDocument(doc); 197 documentManager.saveDocument(doc); 198 199 Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED, parent); 200 201 documentManager.save(); 202 } 203 } catch (IOException e) { 204 log.error("Picture Creation failed", e); 205 documentManager.cancel(); 206 FacesMessage message = FacesMessages.createFacesMessage(FacesMessage.SEVERITY_ERROR, 207 resourcesAccessor.getMessages().get("label.picture.upload.error")); 208 FacesMessages.instance().add(message); 209 return navigationContext.getActionResult(navigationContext.getCurrentDocument(), UserAction.VIEW); 210 } 211 return navigationContext.getActionResult(doc, UserAction.AFTER_CREATE); 212 } 213 214 @Override 215 public String rotate90left() throws IOException { 216 DocumentModel doc = getCurrentDocument(); 217 PictureResourceAdapter picture = doc.getAdapter(PictureResourceAdapter.class); 218 picture.doRotate(-90); 219 documentManager.saveDocument(doc); 220 documentManager.save(); 221 navigationContext.setCurrentDocument(doc); 222 return null; 223 } 224 225 @Override 226 public String rotate90right() throws IOException { 227 DocumentModel doc = getCurrentDocument(); 228 PictureResourceAdapter picture = doc.getAdapter(PictureResourceAdapter.class); 229 picture.doRotate(90); 230 documentManager.saveDocument(doc); 231 documentManager.save(); 232 navigationContext.setCurrentDocument(doc); 233 return null; 234 } 235 236 @Override 237 public String crop() throws IOException { 238 if (cropCoords != null && !cropCoords.equals("")) { 239 DocumentModel doc = getCurrentDocument(); 240 PictureResourceAdapter picture = doc.getAdapter(PictureResourceAdapter.class); 241 picture.doCrop(cropCoords); 242 documentManager.saveDocument(doc); 243 documentManager.save(); 244 navigationContext.setCurrentDocument(doc); 245 } 246 return null; 247 } 248 249 @Override 250 @Observer(value = { EventNames.DOCUMENT_SELECTION_CHANGED, EventNames.DOCUMENT_CHANGED }) 251 @BypassInterceptors 252 public void resetFields() { 253 filename = ""; 254 fileContent = null; 255 selectItems = null; 256 index = 0; 257 cropCoords = null; 258 } 259 260 @WebRemote 261 public String remoteDownload(String patternName, String docID, String blobPropertyName, String filename) 262 { 263 IdRef docref = new IdRef(docID); 264 DocumentModel doc = documentManager.getDocument(docref); 265 return DocumentModelFunctions.fileUrl(patternName, doc, blobPropertyName, filename); 266 } 267 268 @WebRemote 269 public static String urlPopup(String url) { 270 return RestHelper.addCurrentConversationParameters(url); 271 } 272 273 @Override 274 public void download(DocumentView docView) { 275 if (docView != null) { 276 DocumentLocation docLoc = docView.getDocumentLocation(); 277 // fix for NXP-1799 278 if (documentManager == null) { 279 RepositoryLocation loc = new RepositoryLocation(docLoc.getServerName()); 280 navigationContext.setCurrentServerLocation(loc); 281 documentManager = navigationContext.getOrCreateDocumentManager(); 282 } 283 DocumentModel doc = documentManager.getDocument(docLoc.getDocRef()); 284 if (doc == null) { 285 return; 286 } 287 String path = docView.getParameter(DocumentFileCodec.FILE_PROPERTY_PATH_KEY); 288 String[] propertyPath = path.split(":"); 289 String title = null; 290 String field = null; 291 Property datamodel = null; 292 if (propertyPath.length == 2) { 293 title = propertyPath[0]; 294 field = propertyPath[1]; 295 datamodel = doc.getProperty("picture:views"); 296 } else if (propertyPath.length == 3) { 297 String schema = propertyPath[0]; 298 title = propertyPath[1]; 299 field = propertyPath[2]; 300 datamodel = doc.getProperty(schema + ":" + "views"); 301 } 302 Property view = null; 303 for (Property property : datamodel) { 304 if (property.get("title").getValue().equals(title)) { 305 view = property; 306 } 307 } 308 309 if (view == null) { 310 for (Property property : datamodel) { 311 if (property.get("title").getValue().equals("Thumbnail")) { 312 view = property; 313 } 314 } 315 } 316 if (view == null) { 317 return; 318 } 319 Blob blob = (Blob) view.getValue(field); 320 String filename = (String) view.getValue("filename"); 321 // download 322 ComponentUtils.download(doc, path, blob, filename, "picture"); 323 } 324 } 325 326 @Override 327 @Destroy 328 public void destroy() { 329 log.debug("Removing Seam action listener..."); 330 fileurlPicture = null; 331 filename = null; 332 fileContent = null; 333 index = null; 334 selectItems = null; 335 } 336 337 @Override 338 public String getFilename() { 339 return filename; 340 } 341 342 @Override 343 public void setFilename(String filename) { 344 this.filename = filename; 345 } 346 347 @Override 348 public Blob getFileContent() { 349 return fileContent; 350 } 351 352 @Override 353 public void setFileContent(Blob fileContent) { 354 this.fileContent = fileContent; 355 } 356 357 @Override 358 public Integer getIndex() { 359 return index; 360 } 361 362 @Override 363 public void setIndex(Integer index) { 364 this.index = index; 365 } 366 367 @Override 368 public String getCropCoords() { 369 return cropCoords; 370 } 371 372 @Override 373 public void setCropCoords(String cropCoords) { 374 this.cropCoords = cropCoords; 375 } 376 377 public Boolean isImageMagickAvailable() { 378 if (imageMagickAvailable == null) { 379 CommandLineExecutorService cles = Framework.getService(CommandLineExecutorService.class); 380 CommandAvailability ca = cles.getCommandAvailability("cropAndResize"); 381 imageMagickAvailable = ca.isAvailable(); 382 } 383 return imageMagickAvailable; 384 } 385}