001 package de.deepamehta.plugins.images; 002 003 import java.io.File; 004 import java.util.HashSet; 005 import java.util.Set; 006 import java.util.logging.Logger; 007 008 import javax.ws.rs.Consumes; 009 import javax.ws.rs.GET; 010 import javax.ws.rs.HeaderParam; 011 import javax.ws.rs.POST; 012 import javax.ws.rs.Path; 013 import javax.ws.rs.Produces; 014 import javax.ws.rs.QueryParam; 015 import javax.ws.rs.WebApplicationException; 016 import javax.ws.rs.core.Context; 017 import javax.ws.rs.core.MediaType; 018 import javax.ws.rs.core.UriInfo; 019 020 import de.deepamehta.core.ResultSet; 021 import de.deepamehta.core.osgi.PluginActivator; 022 import de.deepamehta.core.service.ClientState; 023 import de.deepamehta.core.service.PluginService; 024 import de.deepamehta.core.service.annotation.ConsumesService; 025 import de.deepamehta.plugins.files.DirectoryListing.FileItem; 026 import de.deepamehta.plugins.files.ItemKind; 027 import de.deepamehta.plugins.files.ResourceInfo; 028 import de.deepamehta.plugins.files.StoredFile; 029 import de.deepamehta.plugins.files.UploadedFile; 030 import de.deepamehta.plugins.files.service.FilesService; 031 032 /** 033 * CKEditor compatible resources for image upload and browse. 034 */ 035 @Path("/images") 036 public class ImagePlugin extends PluginActivator { 037 038 public static final String IMAGES = "images"; 039 040 private static final String FILE_REPOSITORY_PATH = System.getProperty("dm4.filerepo.path"); 041 042 private static Logger log = Logger.getLogger(ImagePlugin.class.getName()); 043 044 private FilesService fileService; 045 046 @Context 047 private UriInfo uriInfo; 048 049 /** 050 * CKEditor image upload integration, see 051 * CKEDITOR.config.filebrowserImageBrowseUrl 052 * 053 * @param image 054 * Uploaded file resource. 055 * @param func 056 * CKEDITOR function number to call. 057 * @param cookie 058 * Actual cookie. 059 * @return JavaScript snippet that calls CKEditor 060 */ 061 @POST 062 @Path("/upload") 063 @Consumes(MediaType.MULTIPART_FORM_DATA) 064 @Produces(MediaType.TEXT_HTML) 065 public String upload(// 066 UploadedFile image,// 067 @QueryParam("CKEditorFuncNum") Long func,// 068 @HeaderParam("Cookie") ClientState cookie) { 069 log.info("upload image " + image.getName()); 070 try { 071 StoredFile file = fileService.storeFile(image, IMAGES, cookie); 072 String path = "/" + IMAGES + "/" + file.getFileName(); 073 return getCkEditorCall(func, getRepoUri(path), ""); 074 } catch (Exception e) { 075 return getCkEditorCall(func, "", e.getMessage()); 076 } 077 } 078 079 /** 080 * Returns a set of all image source URLs. 081 * 082 * @return all image sources 083 */ 084 @GET 085 @Path("/browse") 086 @Produces(MediaType.APPLICATION_JSON) 087 public ResultSet<Image> browse() { 088 log.info("browse images"); 089 Set<Image> images = new HashSet<Image>(); 090 for (FileItem image : fileService.getDirectoryListing(IMAGES).getFileItems()) { 091 String src = getRepoUri(image.getPath()); 092 images.add(new Image(src, image.getMediaType(), image.getSize())); 093 } 094 return new ResultSet<Image>(images.size(), images); 095 } 096 097 /** 098 * Nullify file service reference. 099 */ 100 @Override 101 public void serviceGone(PluginService service) { 102 if (service == fileService) { 103 fileService = null; 104 } 105 } 106 107 /** 108 * Reference the file service and create the repository path if necessary. 109 */ 110 @Override 111 @ConsumesService("de.deepamehta.plugins.files.service.FilesService") 112 public void serviceArrived(PluginService service) { 113 if (service instanceof FilesService) { 114 log.fine("file service arrived"); 115 fileService = (FilesService) service; 116 postInstallMigration(); 117 } 118 } 119 120 private void postInstallMigration() { 121 // TODO move the initialization to migration "0" 122 try { 123 // check image file repository 124 ResourceInfo resourceInfo = fileService.getResourceInfo(IMAGES); 125 if (resourceInfo.getItemKind() != ItemKind.DIRECTORY) { 126 String message = "image storage directory " + FILE_REPOSITORY_PATH + File.separator 127 + IMAGES + " can not be used"; 128 throw new IllegalStateException(message); 129 } 130 } catch (WebApplicationException e) { 131 // catch fileService info request error 132 if (e.getResponse().getStatus() != 404) { 133 throw e; 134 } else { 135 log.info("create image directory"); 136 fileService.createFolder(IMAGES, "/"); 137 } 138 } 139 } 140 141 /** 142 * Returns a in-line JavaScript snippet that calls the parent CKEditor. 143 * 144 * @param func 145 * CKEDITOR function number. 146 * @param uri 147 * Resource URI. 148 * @param error 149 * Error message. 150 * @return JavaScript snippet that calls CKEditor 151 */ 152 private String getCkEditorCall(Long func, String uri, String error) { 153 return "<script type='text/javascript'>" + "window.parent.CKEDITOR.tools.callFunction(" 154 + func + ", '" + uri + "', '" + error + "')" + "</script>"; 155 } 156 157 /** 158 * Returns an external accessible file repository URI of path based on 159 * actual request URI. 160 * 161 * @param path 162 * Relative path of a file repository resource. 163 * @return URI 164 */ 165 private String getRepoUri(String path) { 166 return uriInfo.getBaseUri() + "filerepo" + path; 167 } 168 }