1 package org.exoplatform.wcm.connector.collaboration;
2
3 import java.io.FileNotFoundException;
4 import java.security.AccessControlException;
5 import java.util.Locale;
6 import java.util.ResourceBundle;
7
8 import javax.jcr.AccessDeniedException;
9 import javax.jcr.Node;
10 import javax.jcr.RepositoryException;
11 import javax.jcr.Session;
12 import javax.jcr.Value;
13 import javax.jcr.lock.LockException;
14 import javax.ws.rs.FormParam;
15 import javax.ws.rs.POST;
16 import javax.ws.rs.Path;
17 import javax.ws.rs.QueryParam;
18 import javax.ws.rs.core.CacheControl;
19 import javax.ws.rs.core.MediaType;
20 import javax.ws.rs.core.Response;
21 import javax.xml.parsers.DocumentBuilderFactory;
22 import javax.xml.transform.dom.DOMSource;
23
24 import org.exoplatform.container.xml.PortalContainerInfo;
25 import org.exoplatform.ecm.utils.text.Text;
26 import org.exoplatform.services.jcr.RepositoryService;
27 import org.exoplatform.services.jcr.access.PermissionType;
28 import org.exoplatform.services.jcr.core.ExtendedNode;
29 import org.exoplatform.services.jcr.core.ManageableRepository;
30 import org.exoplatform.services.jcr.ext.common.SessionProvider;
31 import org.exoplatform.services.listener.ListenerService;
32 import org.exoplatform.services.log.ExoLogger;
33 import org.exoplatform.services.log.Log;
34 import org.exoplatform.services.resources.ResourceBundleService;
35 import org.exoplatform.services.rest.resource.ResourceContainer;
36 import org.exoplatform.services.security.ConversationState;
37 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40
41
42
43
44
45
46
47
48
49 @Path("/contents/editing/")
50 public class InlineEditingService implements ResourceContainer{
51 private static final Log LOG = ExoLogger.getLogger(InlineEditingService.class.getName());
52
53 final static public String EXO_TITLE = "exo:title";
54
55 final static public String EXO_SUMMARY = "exo:summary";
56
57 final static public String EXO_TEXT = "exo:text";
58
59 final static public String EXO_RSS_ENABLE = "exo:rss-enable";
60
61 public final static String POST_EDIT_CONTENT_EVENT = "CmsService.event.postEdit";
62
63 private final String localeFile = "locale.portlet.i18n.WebUIDms";
64
65
66
67
68
69
70
71
72
73
74
75 @POST
76 @Path("/title/")
77 public Response editTitle(@FormParam("newValue") String newTitle,
78 @QueryParam("repositoryName") String repositoryName,
79 @QueryParam("workspaceName") String workspaceName,
80 @QueryParam("nodeUIID") String nodeUIID,
81 @QueryParam("siteName") String siteName,
82 @QueryParam("language") String language){
83 return modifyProperty(EXO_TITLE, newTitle, repositoryName, workspaceName, nodeUIID, siteName, language);
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97 @POST
98 @Path("/summary/")
99 public Response editSummary(@FormParam("newValue") String newSummary,
100 @QueryParam("repositoryName") String repositoryName,
101 @QueryParam("workspaceName") String workspaceName,
102 @QueryParam("nodeUIID") String nodeUIID,
103 @QueryParam("siteName") String siteName,
104 @QueryParam("language") String language){
105 return modifyProperty(EXO_SUMMARY, newSummary, repositoryName, workspaceName, nodeUIID, siteName, language);
106 }
107
108
109
110
111
112
113
114
115
116
117
118 @POST
119 @Path("/text/")
120 public Response editText( @FormParam("newValue") String newValue,
121 @QueryParam("repositoryName") String repositoryName,
122 @QueryParam("workspaceName") String workspaceName,
123 @QueryParam("nodeUIID") String nodeUIID,
124 @QueryParam("siteName") String siteName,
125 @QueryParam("language") String language){
126 return modifyProperty(EXO_TEXT, newValue, repositoryName, workspaceName, nodeUIID, siteName, language);
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141 @POST
142 @Path("/property/")
143 public Response editProperty( @QueryParam("propertyName") String propertyName,
144 @FormParam("newValue") String newValue,
145 @QueryParam("repositoryName") String repositoryName,
146 @QueryParam("workspaceName") String workspaceName,
147 @QueryParam("nodeUIID") String nodeUIID,
148 @QueryParam("siteName") String siteName,
149 @QueryParam("language") String language){
150 String decodedPropertyName = Text.unescapeIllegalJcrChars(propertyName);
151 return modifyProperty(decodedPropertyName, newValue, repositoryName, workspaceName, nodeUIID, siteName, language);
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165 public Response modifyProperty(String propertyName, String newValue, String repositoryName, String workspaceName,
166 String nodeUIID,String siteName, String language){
167 ResourceBundle resourceBundle = null;
168 String messageKey = "";
169 String message = "";
170 Document document = null;
171 Element localeMsg = null;
172 try {
173 Locale locale = new Locale(language);
174 ResourceBundleService resourceBundleService = WCMCoreUtils.getService(ResourceBundleService.class);
175 resourceBundle = resourceBundleService.getResourceBundle(localeFile, locale);
176 } catch(Exception ex) {
177 if (LOG.isErrorEnabled()) {
178 LOG.error("Error when perform create ResourceBundle: ", ex);
179 }
180 }
181 try {
182 document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
183 } catch(Exception ex) {
184 if (LOG.isErrorEnabled()) {
185 LOG.error("Error when perform create Document object: ", ex);
186 }
187 }
188 CacheControl cacheControl = new CacheControl();
189 cacheControl.setNoCache(true);
190 cacheControl.setNoStore(true);
191 try {
192 SessionProvider sessionProvider = WCMCoreUtils.getUserSessionProvider();
193 RepositoryService repositoryService = WCMCoreUtils.getService(RepositoryService.class);
194 ManageableRepository manageableRepository = repositoryService.getCurrentRepository();
195 Session session = sessionProvider.getSession(workspaceName, manageableRepository);
196 try {
197 localeMsg = document.createElement("bundle");
198 Node node = session.getNodeByUUID(nodeUIID);
199 node = (Node)session.getItem(node.getPath());
200 if(canSetProperty(node)) {
201 if (!sameValue(newValue, node, propertyName)) {
202 if (newValue.length() > 0) {
203 newValue = Text.unescapeIllegalJcrChars(newValue.trim());
204 PortalContainerInfo containerInfo = WCMCoreUtils.getService(PortalContainerInfo.class);
205 String containerName = containerInfo.getContainerName();
206 ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class, containerName);
207 if (propertyName.equals(EXO_TITLE)) {
208 if (!node.hasProperty(EXO_TITLE))
209 node.addMixin(EXO_RSS_ENABLE);
210 }
211 if (!propertyName.contains("/")) {
212 if (node.hasProperty(propertyName) && node.getProperty(propertyName).getDefinition().isMultiple()) {
213 Value[] currentValue = node.getProperty(propertyName).getValues();
214 if (currentValue==null) currentValue = new Value[1];
215 currentValue[0] = session.getValueFactory().createValue(newValue);
216 node.setProperty(propertyName, currentValue);
217 }else {
218 node.setProperty(propertyName, newValue);
219 }
220 } else {
221 int iSlash = propertyName.lastIndexOf("/");
222 String subnodePath = propertyName.substring(0, iSlash);
223 String subnodeProperty = propertyName.substring(iSlash+1);
224 Node subnode = node.getNode(subnodePath);
225 if (subnode.hasProperty(subnodeProperty) && subnode.getProperty(subnodeProperty).getDefinition().isMultiple()) {
226 Value[] currentValue = subnode.getProperty(subnodeProperty).getValues();
227 if (currentValue==null) currentValue = new Value[1];
228 currentValue[0] = session.getValueFactory().createValue(newValue);
229 subnode.setProperty(subnodeProperty, currentValue);
230 } else {
231 subnode.setProperty(subnodeProperty, newValue);
232 }
233 }
234 ConversationState conversationState = ConversationState.getCurrent();
235 conversationState.setAttribute("siteName", siteName);
236 listenerService.broadcast(POST_EDIT_CONTENT_EVENT, null, node);
237 node.save();
238 }
239 }
240 } else {
241 messageKey = "AccessDeniedException.msg";
242 message = resourceBundle.getString(messageKey);
243 localeMsg.setAttribute("message", message);
244 document.appendChild(localeMsg);
245 return Response.ok(new DOMSource(document), MediaType.TEXT_XML).cacheControl(cacheControl).build();
246 }
247 } catch (AccessDeniedException ace) {
248 if (LOG.isErrorEnabled()) {
249 LOG.error("AccessDeniedException: ", ace);
250 }
251 messageKey = "AccessDeniedException.msg";
252 message = resourceBundle.getString(messageKey);
253 localeMsg.setAttribute("message", message);
254 document.appendChild(localeMsg);
255 return Response.ok(new DOMSource(document), MediaType.TEXT_XML).cacheControl(cacheControl).build();
256 } catch (FileNotFoundException fie) {
257 if (LOG.isErrorEnabled()) {
258 LOG.error("FileNotFoundException: ", fie);
259 }
260 messageKey = "ItemNotFoundException.msg";
261 message = resourceBundle.getString(messageKey);
262 localeMsg.setAttribute("message", message);
263 document.appendChild(localeMsg);
264 return Response.ok(new DOMSource(document), MediaType.TEXT_XML).cacheControl(cacheControl).build();
265 } catch (LockException lockex) {
266 if (LOG.isErrorEnabled()) {
267 LOG.error("LockException", lockex);
268 }
269 messageKey = "LockException.msg";
270 message = resourceBundle.getString(messageKey);
271 localeMsg.setAttribute("message", message);
272 document.appendChild(localeMsg);
273 return Response.ok(new DOMSource(document), MediaType.TEXT_XML).cacheControl(cacheControl).build();
274 }
275 } catch (Exception e) {
276 if (LOG.isErrorEnabled()) {
277 LOG.error("Error when perform edit title: ", e);
278 }
279 messageKey = "UIPresentation.label.Exception";
280 message = resourceBundle.getString(messageKey);
281 localeMsg.setAttribute("message", message);
282 document.appendChild(localeMsg);
283 return Response.ok(new DOMSource(document), MediaType.TEXT_XML).cacheControl(cacheControl).build();
284 }
285 localeMsg.setAttribute("message", "OK");
286 document.appendChild(localeMsg);
287 return Response.ok(new DOMSource(document), MediaType.TEXT_XML).cacheControl(cacheControl).build();
288 }
289
290
291
292
293
294
295
296
297
298
299 private boolean sameValue(String newValue, Node node, String propertyName) throws Exception {
300 if (!node.hasProperty(propertyName))
301 return (newValue == null || newValue.length() == 0);
302 if (node.getProperty(propertyName).getDefinition().isMultiple()){
303 try {
304 return node.getProperty(propertyName).getValues()[0].getString().equals(newValue);
305 }catch (Exception e) {
306 return false;
307 }
308 }
309 return node.getProperty(propertyName).getString().equals(newValue);
310 }
311
312
313
314
315
316
317
318
319 public static boolean canSetProperty(Node node) throws RepositoryException {
320 return checkPermission(node,PermissionType.SET_PROPERTY);
321 }
322
323 private static boolean checkPermission(Node node,String permissionType) throws RepositoryException {
324 try {
325 ((ExtendedNode)node).checkPermission(permissionType);
326 return true;
327 } catch(AccessControlException e) {
328 return false;
329 }
330 }
331 }