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 }