001package de.deepamehta.plugins.images; 002 003import de.deepamehta.core.osgi.PluginActivator; 004import de.deepamehta.core.service.Inject; 005import de.deepamehta.core.Topic; 006import de.deepamehta.core.service.ResultList; 007import de.deepamehta.core.service.Transactional; 008import de.deepamehta.plugins.files.DirectoryListing.FileItem; 009import de.deepamehta.plugins.files.*; 010 011import javax.ws.rs.*; 012import javax.ws.rs.core.Context; 013import javax.ws.rs.core.MediaType; 014import javax.ws.rs.core.UriInfo; 015import javax.ws.rs.ext.RuntimeDelegate; 016import java.io.File; 017import java.util.ArrayList; 018import java.util.logging.Logger; 019 020/** 021 * CKEditor compatible resources for image upload and browse. 022 */ 023@Path("/images") 024public class ImagePlugin extends PluginActivator { 025 026 private static Logger log = Logger.getLogger(ImagePlugin.class.getName()); 027 028 public static final String FILEREPO_BASE_URI_NAME = "filerepo"; 029 public static final String FILEREPO_IMAGES_SUBFOLDER = "images"; 030 public static final String DM4_HOST_URL = System.getProperty("dm4.host.url"); 031 // public static final String FILE_REPOSITORY_PATH = System.getProperty("dm4.filerepo.path"); 032 033 @Inject 034 private FilesService fileService; 035 036 @Context 037 private UriInfo uriInfo; 038 039 /** 040 * CKEditor image upload integration, see 041 * CKEDITOR.config.filebrowserImageBrowseUrl 042 * 043 * @param image 044 * Uploaded file resource. 045 * @param func 046 * CKEDITOR function number to call. 047 * @return JavaScript snippet that calls CKEditor 048 */ 049 @POST 050 @Path("/upload") 051 @Consumes(MediaType.MULTIPART_FORM_DATA) 052 @Produces(MediaType.TEXT_HTML) 053 @Transactional 054 public String upload(UploadedFile image, @QueryParam("CKEditorFuncNum") Long func) { 055 log.info("upload image " + image.getName()); 056 createImagesDirectoryInFileRepo(); 057 try { 058 StoredFile file = fileService.storeFile(image, prefix() + File.separator + FILEREPO_IMAGES_SUBFOLDER); 059 String path = prefix() + File.separator + FILEREPO_IMAGES_SUBFOLDER + File.separator + file.getFileName(); 060 return getCkEditorCall(func, getRepoUri(path), ""); 061 } catch (Exception e) { 062 log.severe(e.getMessage() + ", caused by " + e.getCause().getMessage()); 063 return getCkEditorCall(func, "", e.getMessage()); 064 } 065 } 066 067 /** 068 * Returns a set of all image source URLs. 069 * 070 * @return all image sources 071 */ 072 @GET 073 @Path("/browse") 074 @Produces(MediaType.APPLICATION_JSON) 075 public ResultList<Image> browse() { 076 log.info("browse images in repository path " + prefix() + File.separator + FILEREPO_IMAGES_SUBFOLDER); 077 createImagesDirectoryInFileRepo(); 078 try { 079 ArrayList<Image> images = new ArrayList<Image>(); 080 DirectoryListing imagesDirectory= fileService.getDirectoryListing(prefix() + File.separator + 081 FILEREPO_IMAGES_SUBFOLDER); 082 for (FileItem image : imagesDirectory.getFileItems()) { 083 String src = getRepoUri(image.getPath()); 084 images.add(new Image(src, image.getMediaType(), image.getSize(), image.getName())); 085 } 086 return new ResultList<Image>(images.size(), images); 087 } catch (WebApplicationException e) { // fileService.getDirectoryListing 088 throw e; // do not wrap it again 089 } catch (Exception e) { 090 throw new RuntimeException(e); 091 } 092 } 093 094 private void createImagesDirectoryInFileRepo() { 095 try { 096 // check image file repository 097 ResourceInfo resourceInfo = fileService.getResourceInfo(prefix() + File.separator + 098 FILEREPO_IMAGES_SUBFOLDER); 099 // depending on prefix() we check for an "images" folder in the global or workspace filerepo 100 if (resourceInfo.getItemKind() != ItemKind.DIRECTORY) { 101 String message = "ImagePlugin: \"images\" storage directory in repo path " + fileService.getFile("/") + 102 prefix() + File.separator + ImagePlugin.FILEREPO_IMAGES_SUBFOLDER + " can not be used"; 103 throw new IllegalStateException(message); 104 } 105 } catch (WebApplicationException e) { 106 log.info("Created the \"images\" subfolder on the fly for new filerepo in " + fileService.getFile("/") + 107 prefix() + File.separator + FILEREPO_IMAGES_SUBFOLDER + "!"); 108 try { 109 fileService.createFolder(FILEREPO_IMAGES_SUBFOLDER, prefix()); 110 } catch (RuntimeException ex) { 111 log.warning("RuntimeException caught during folder creation, presumably the folder " + 112 "must already EXIST, so OK:" + ex.getMessage()); 113 } 114 // catch fileService create request failed because of: folder exists 115 } catch (Exception e) { 116 throw new RuntimeException(e); 117 } 118 } 119 120 /** 121 * Returns a in-line JavaScript snippet that calls the parent CKEditor. 122 * 123 * @param func 124 * CKEDITOR function number. 125 * @param uri 126 * Resource URI. 127 * @param error 128 * Error message. 129 * @return JavaScript snippet that calls CKEditor 130 */ 131 private String getCkEditorCall(Long func, String uri, String error) { 132 return "<script type='text/javascript'>" + "window.parent.CKEDITOR.tools.callFunction(" 133 + func + ", '" + uri + "', '" + error + "')" + "</script>"; 134 } 135 136 /** 137 * Returns an external accessible file repository URI of path based on the 138 * <code>dm4.host.url</code> platform configuration option. 139 * 140 * @param path 141 * Relative path of a file repository resource. 142 * @return URI 143 */ 144 private String getRepoUri(String path) { 145 return DM4_HOST_URL + FILEREPO_BASE_URI_NAME + path; 146 } 147 148 private String prefix() { 149 File repo = fileService.getFile("/"); 150 return ((FilesPlugin) fileService).repoPath(repo); 151 } 152 153}