1 package org.exoplatform.wcm.connector.collaboration;
2
3 import org.apache.commons.lang.StringUtils;
4 import org.apache.tika.io.IOUtils;
5 import org.exoplatform.ecm.utils.text.Text;
6 import org.exoplatform.services.cms.documents.DocumentTypeService;
7 import org.exoplatform.services.cms.documents.impl.DocumentType;
8 import org.exoplatform.services.cms.link.LinkManager;
9 import org.exoplatform.services.cms.link.NodeFinder;
10 import org.exoplatform.services.log.ExoLogger;
11 import org.exoplatform.services.log.Log;
12 import org.exoplatform.services.resources.ResourceBundleService;
13 import org.exoplatform.services.rest.resource.ResourceContainer;
14 import org.exoplatform.services.wcm.core.NodetypeConstant;
15 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
16 import org.json.JSONObject;
17 import org.picocontainer.Startable;
18
19 import javax.annotation.security.RolesAllowed;
20 import javax.jcr.Node;
21 import javax.jcr.PathNotFoundException;
22 import javax.jcr.RepositoryException;
23 import javax.jcr.Session;
24 import javax.servlet.http.HttpServletRequest;
25 import javax.ws.rs.*;
26 import javax.ws.rs.core.*;
27 import java.net.URLDecoder;
28 import java.util.Locale;
29 import java.util.MissingResourceException;
30 import java.util.ResourceBundle;
31
32
33
34
35
36
37
38
39
40
41 @Path("/office/")
42 @RolesAllowed("users")
43 public class OpenInOfficeConnector implements ResourceContainer, Startable {
44
45 private Log log = ExoLogger.getExoLogger(OpenInOfficeConnector.class);
46 private final String OPEN_DOCUMENT_ON_DESKTOP_ICO = "uiIconOpenOnDesktop";
47 private final String CONNECTOR_BUNDLE_LOCATION = "locale.wcm.resources.WCMResourceBundleConnector";
48 private final String OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY = "OpenInOfficeConnector.label.exo.remote-edit.desktop";
49 private final String OPEN_DOCUMENT_IN_DESKTOP_APP_RESOURCE_KEY = "OpenInOfficeConnector.label.exo.remote-edit.desktop-app";
50 private final String OPEN_DOCUMENT_DEFAULT_TITLE = "Open on Desktop";
51 private final int CACHED_TIME = 60*24*30*12;
52
53 private static final String VERSION_MIXIN ="mix:versionable";
54
55 private NodeFinder nodeFinder;
56 private LinkManager linkManager;
57 private ResourceBundleService resourceBundleService;
58 private DocumentTypeService documentTypeService;
59
60 public OpenInOfficeConnector(NodeFinder nodeFinder,
61 LinkManager linkManager,
62 ResourceBundleService resourceBundleService,
63 DocumentTypeService documentTypeService){
64 this.nodeFinder = nodeFinder;
65 this.linkManager = linkManager;
66 this.resourceBundleService = resourceBundleService;
67 this.documentTypeService = documentTypeService;
68 }
69
70
71
72
73
74
75
76 @GET
77 @Path("/updateDocumentTitle")
78 public Response updateDocumentTitle(
79 @Context Request request,
80 @QueryParam("objId") String objId,
81 @QueryParam("lang") String language) throws Exception {
82
83
84 int indexColon = objId.indexOf(":/");
85 if(indexColon < 0) {
86 return Response.status(Response.Status.BAD_REQUEST)
87 .entity("The objId param must start by the workspace name, followed by ':' and the node path").build();
88 }
89 String workspace = objId.substring(0, indexColon);
90 String filePath = objId.substring(indexColon + 1);
91
92 String extension = filePath.substring(filePath.lastIndexOf(".") + 1, filePath.length());
93 if(extension.contains("[")) extension=extension.substring(0, extension.indexOf("["));
94 EntityTag etag = new EntityTag(Integer.toString((extension+"_"+language).hashCode()));
95 Response.ResponseBuilder builder = request.evaluatePreconditions(etag);
96 if(builder!=null) return builder.build();
97
98
99
100 CacheControl cc = new CacheControl();
101 cc.setMaxAge(CACHED_TIME);
102
103 ResourceBundle resourceBundle = resourceBundleService.getResourceBundle(CONNECTOR_BUNDLE_LOCATION, new Locale(language));
104 String title = resourceBundle!=null?resourceBundle.getString(OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY):OPEN_DOCUMENT_DEFAULT_TITLE;
105 String ico = OPEN_DOCUMENT_ON_DESKTOP_ICO;
106
107 DocumentType documentType = documentTypeService.getDocumentType(extension);
108
109 if(documentType !=null && resourceBundle !=null ){
110 try {
111 if(!StringUtils.isEmpty(resourceBundle.getString(documentType.getResourceBundleKey())))
112 title = resourceBundle.getString(documentType.getResourceBundleKey());
113 }catch(MissingResourceException ex){
114 String _openonDesktop = resourceBundle.getString(OPEN_DOCUMENT_IN_DESKTOP_APP_RESOURCE_KEY);
115 if(_openonDesktop!=null && _openonDesktop.contains("{0}")) {
116 title = _openonDesktop.replace("{0}", documentType.getResourceBundleKey());
117 }else{
118 title = OPEN_DOCUMENT_DEFAULT_TITLE;
119 }
120 }
121 if(!StringUtils.isEmpty(documentType.getIconClass())) ico=documentType.getIconClass();
122 }
123 Node node;
124 String nodePath = filePath;
125 boolean isFile=false;
126 try{
127 try {
128 node = (Node)nodeFinder.getItem(workspace, filePath);
129 } catch (PathNotFoundException e) {
130 node = (Node)nodeFinder.getItem(workspace, Text.unescapeIllegalJcrChars(filePath));
131 }
132 if (linkManager.isLink(node)) node = linkManager.getTarget(node);
133 nodePath = node.getPath();
134 isFile = node.isNodeType(NodetypeConstant.NT_FILE);
135 }catch(RepositoryException ex){
136 if(log.isErrorEnabled()){log.error("Exception when get node with path: "+filePath, ex);}
137 }
138
139 boolean isMsoffice = false;
140 if (documentType.getResourceBundleKey() != OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY) {
141 isMsoffice = true;
142 }
143 JSONObject rs = new JSONObject();
144 rs.put("ico", ico);
145 rs.put("title", title);
146 rs.put("repository", WCMCoreUtils.getRepository().getConfiguration().getName());
147 rs.put("workspace", workspace);
148 rs.put("filePath", nodePath);
149 rs.put("isFile", isFile);
150 rs.put("isMsoffice", isMsoffice);
151
152 builder = Response.ok(rs.toString(), MediaType.APPLICATION_JSON);
153 builder.tag(etag);
154 builder.cacheControl(cc);
155 return builder.build();
156 }
157
158
159
160
161
162
163 public String[] getDocumentInfos(String fileName){
164 String title = OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY;
165 String icon = OPEN_DOCUMENT_ON_DESKTOP_ICO;
166
167 String _extension = "";
168 if(fileName.lastIndexOf(".") > 0 ) {
169 _extension = StringUtils.substring(fileName, fileName.lastIndexOf(".") + 1, fileName.length());
170 }
171 if(StringUtils.isBlank(_extension)) return new String[]{title, icon};
172
173 DocumentType documentType = documentTypeService.getDocumentType(_extension);
174 if(documentType !=null){
175 if(!StringUtils.isEmpty(documentType.getResourceBundleKey())) title=documentType.getResourceBundleKey();
176 if(!StringUtils.isEmpty(documentType.getIconClass())) icon=documentType.getIconClass();
177 }
178 return new String[]{title, icon};
179 }
180
181
182
183
184
185
186
187
188 @GET
189 @Path("/checkout")
190 public Response checkout(@Context Request request,
191 @QueryParam("filePath") String filePath,
192 @QueryParam("workspace") String workspace
193 ) throws Exception {
194 Session session = WCMCoreUtils.getSystemSessionProvider().
195 getSession(workspace, WCMCoreUtils.getRepository());
196 Node node = (Node)session.getItem(filePath);
197
198 if(node.canAddMixin(VERSION_MIXIN)){
199 node.addMixin(VERSION_MIXIN);
200 node.save();
201 node.checkin();
202 node.checkout();
203 }
204
205 if(!node.isCheckedOut()) node.checkout();
206
207 return Response.ok(String.valueOf(node.isCheckedOut()), MediaType.TEXT_PLAIN).build();
208 }
209
210
211
212
213
214
215
216
217 @GET
218 @Path("/{linkFilePath}/")
219 @Produces("application/internet-shortcut")
220 public Response createShortcut(@Context HttpServletRequest httpServletRequest,
221 @PathParam("linkFilePath") String linkFilePath,
222 @QueryParam("filePath") String filePath,
223 @QueryParam("workspace") String workspace
224 ) throws Exception {
225 Session session = WCMCoreUtils.getSystemSessionProvider().getSession(workspace, WCMCoreUtils.getRepository());
226 Node node = (Node)session.getItem(filePath);
227 String repo = WCMCoreUtils.getRepository().getConfiguration().getName();
228
229 String obsPath = httpServletRequest.getScheme()+ "://" + httpServletRequest.getServerName() + ":"
230 +httpServletRequest.getServerPort() + "/"
231 + WCMCoreUtils.getRestContextName()+ "/private/jcr/" + repo + "/" + workspace + node.getPath();
232
233 String shortCutContent = "[InternetShortcut]\n";
234 shortCutContent+="URL="+obsPath+"\n";
235 return Response.ok(IOUtils.toInputStream(shortCutContent), MediaType.APPLICATION_OCTET_STREAM)
236 .header("Content-Disposition","attachment; filename="+node.getName()+".url")
237 .header("Content-type", "application/internet-shortcut")
238 .build();
239 }
240
241 @Override
242 public void start() {
243 }
244
245 @Override
246 public void stop() { }
247 }