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