1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.wcm.connector.collaboration;
18
19 import org.apache.commons.lang.StringUtils;
20 import org.exoplatform.common.http.HTTPStatus;
21 import org.exoplatform.ecm.utils.text.Text;
22 import org.exoplatform.services.cms.CmsService;
23 import org.exoplatform.services.cms.impl.Utils;
24 import org.exoplatform.services.cms.link.NodeFinder;
25 import org.exoplatform.services.cms.lock.LockService;
26 import org.exoplatform.services.cms.relations.RelationsService;
27 import org.exoplatform.services.jcr.ext.common.SessionProvider;
28 import org.exoplatform.services.listener.ListenerService;
29 import org.exoplatform.services.log.ExoLogger;
30 import org.exoplatform.services.log.Log;
31 import org.exoplatform.services.rest.resource.ResourceContainer;
32 import org.exoplatform.services.wcm.core.NodetypeConstant;
33 import org.exoplatform.services.wcm.publication.WCMPublicationService;
34 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
35
36 import javax.annotation.security.RolesAllowed;
37 import javax.jcr.Node;
38 import javax.jcr.NodeIterator;
39 import javax.jcr.Property;
40 import javax.jcr.PropertyIterator;
41 import javax.jcr.Session;
42 import javax.jcr.lock.LockException;
43 import javax.ws.rs.GET;
44 import javax.ws.rs.Path;
45 import javax.ws.rs.QueryParam;
46 import javax.ws.rs.core.MediaType;
47 import javax.ws.rs.core.Response;
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.regex.Matcher;
51 import java.util.regex.Pattern;
52
53
54
55
56
57
58
59
60
61
62
63 @Path("/contents/rename/")
64 public class RenameConnector implements ResourceContainer {
65
66 private static final Log LOG = ExoLogger.getLogger(RenameConnector.class.getName());
67
68 private static final Pattern FILE_EXPLORER_URL_SYNTAX = Pattern.compile("([^:/]+):(/.*)");
69
70 private static final String RELATION_PROP = "exo:relation";
71
72 private static final String DEFAULT_NAME = "untitled";
73
74
75
76
77
78
79
80
81
82
83
84
85 @GET
86 @Path("/getObjectId/")
87 public Response getObjectId(@QueryParam("nodePath") String nodePath) throws Exception {
88 return Response.ok(Utils.getObjectId(nodePath), MediaType.TEXT_PLAIN).build();
89 }
90
91
92
93
94
95
96
97
98
99
100
101 @GET
102 @Path("/rename/")
103 @RolesAllowed("users")
104 public Response rename(@QueryParam("oldPath") String oldPath,
105 @QueryParam("newTitle") String newTitle) throws Exception {
106 try {
107
108 if (StringUtils.isBlank(newTitle)) {
109 return Response.status(HTTPStatus.BAD_REQUEST).build();
110 }
111 String newExoTitle = newTitle;
112
113 String newName = Text.escapeIllegalJcrChars(newTitle);
114
115
116 newName = (StringUtils.isEmpty(newName)) ? DEFAULT_NAME : newName;
117
118
119 String[] workspaceAndPath = parseWorkSpaceNameAndNodePath(oldPath);
120 Node renamedNode = (Node)WCMCoreUtils.getService(NodeFinder.class)
121 .getItem(this.getSession(workspaceAndPath[0]), workspaceAndPath[1], false);
122
123 String oldName = renamedNode.getName();
124 if (oldName.indexOf('.') != -1 && renamedNode.isNodeType(NodetypeConstant.NT_FILE)) {
125 String ext = oldName.substring(oldName.lastIndexOf('.'));
126 newName = newName.concat(ext);
127 newExoTitle = newExoTitle.concat(ext);
128 }
129
130
131 String oldExoTitle = (renamedNode.hasProperty("exo:title")) ? renamedNode.getProperty("exo:title")
132 .getString()
133 : StringUtils.EMPTY;
134 CmsService cmsService = WCMCoreUtils.getService(CmsService.class);
135 cmsService.getPreProperties().clear();
136 String nodeUUID = "";
137 if(renamedNode.isNodeType(NodetypeConstant.MIX_REFERENCEABLE)) nodeUUID = renamedNode.getUUID();
138 cmsService.getPreProperties().put(nodeUUID + "_" + "exo:title", oldExoTitle);
139
140 if (renamedNode.getName().equals(newName) && oldExoTitle.equals(newExoTitle)) {
141 return Response.status(HTTPStatus.BAD_REQUEST).build();
142 }
143
144
145 if (!this.canEditLockedNode(renamedNode)) {
146 return Response.status(HTTPStatus.BAD_REQUEST).build();
147 }
148
149
150 if (renamedNode.canAddMixin(NodetypeConstant.MIX_REFERENCEABLE)) {
151 renamedNode.addMixin(NodetypeConstant.MIX_REFERENCEABLE);
152 renamedNode.save();
153 }
154 String uuid = renamedNode.getUUID();
155
156
157 Session nodeSession = renamedNode.getSession();
158 if (!renamedNode.getName().equals(newName)) {
159
160 List<Node> refList = new ArrayList<Node>();
161 PropertyIterator references = renamedNode.getReferences();
162 RelationsService relationsService = WCMCoreUtils.getService(RelationsService.class);
163 while (references.hasNext()) {
164 Property pro = references.nextProperty();
165 Node refNode = pro.getParent();
166 if (refNode.hasProperty(RELATION_PROP)) {
167 refList.add(refNode);
168 relationsService.removeRelation(refNode, renamedNode.getPath());
169 }
170 }
171
172
173 Node parent = renamedNode.getParent();
174 String srcPath = renamedNode.getPath();
175 String destPath = (parent.getPath().equals("/") ? StringUtils.EMPTY : parent.getPath()) + "/"
176 + newName;
177
178 this.addLockToken(renamedNode.getParent());
179 nodeSession.getWorkspace().move(srcPath, destPath);
180
181
182 Node destNode = nodeSession.getNodeByUUID(uuid);
183
184
185 for (Node addRef : refList) {
186 relationsService.addRelation(addRef, destNode.getPath(), nodeSession.getWorkspace().getName());
187 }
188
189
190 if (destNode.isLocked()) {
191 WCMCoreUtils.getService(LockService.class).changeLockToken(renamedNode, destNode);
192 }
193 this.changeLockForChild(srcPath, destNode);
194
195
196 if (destNode.canAddMixin("exo:modify")) {
197 destNode.addMixin("exo:modify");
198 }
199 destNode.setProperty("exo:lastModifier", nodeSession.getUserID());
200
201
202 if(renamedNode.canAddMixin("exo:sortable")) {
203 renamedNode.addMixin("exo:sortable");
204 }
205 renamedNode.setProperty("exo:name", renamedNode.getName());
206
207 renamedNode = destNode;
208 }
209
210
211 if (!renamedNode.hasProperty("exo:title")) {
212 renamedNode.addMixin(NodetypeConstant.EXO_RSS_ENABLE);
213 }
214 renamedNode.setProperty("exo:title", newExoTitle);
215
216 nodeSession.save();
217
218
219 WCMPublicationService publicationService = WCMCoreUtils.getService(WCMPublicationService.class);
220 if (publicationService.isEnrolledInWCMLifecycle(renamedNode)) {
221 ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class);
222 listenerService.broadcast(CmsService.POST_EDIT_CONTENT_EVENT, this, renamedNode);
223 }
224
225 return Response.ok(uuid).build();
226 } catch (LockException e) {
227 if (LOG.isWarnEnabled()) {
228 LOG.warn("The node or parent node is locked. Rename is not successful!");
229 }
230 } catch (Exception e) {
231 if (LOG.isDebugEnabled()) {
232 LOG.debug("Rename is not successful!", e);
233 } else if (LOG.isWarnEnabled()) {
234 LOG.warn("Rename is not successful!");
235 }
236 }
237 return Response.status(HTTPStatus.BAD_REQUEST).build();
238 }
239
240
241
242
243
244
245
246
247 private void changeLockForChild(String srcPath, Node parentNewNode) throws Exception {
248 if(parentNewNode.hasNodes()) {
249 NodeIterator newNodeIter = parentNewNode.getNodes();
250 String newSRCPath = null;
251 while(newNodeIter.hasNext()) {
252 Node newChildNode = newNodeIter.nextNode();
253 newSRCPath = newChildNode.getPath().replace(parentNewNode.getPath(), srcPath);
254 if(newChildNode.isLocked()) WCMCoreUtils.getService(LockService.class).changeLockToken(newSRCPath, newChildNode);
255 if(newChildNode.hasNodes()) changeLockForChild(newSRCPath, newChildNode);
256 }
257 }
258 }
259
260
261
262
263
264
265
266
267 private boolean canEditLockedNode(Node node) throws Exception {
268 LockService lockService = WCMCoreUtils.getService(LockService.class);
269 if(!node.isLocked()) return true;
270 String lockToken = lockService.getLockTokenOfUser(node);
271 if(lockToken != null) {
272 node.getSession().addLockToken(lockService.getLockToken(node));
273 return true;
274 }
275 return false;
276 }
277
278
279
280
281
282
283
284 private void addLockToken(Node node) throws Exception {
285 if (node.isLocked()) {
286 String lockToken = WCMCoreUtils.getService(LockService.class).getLockToken(node);
287 if(lockToken != null) {
288 node.getSession().addLockToken(lockToken);
289 }
290 }
291 }
292
293
294
295
296
297
298
299 private String[] parseWorkSpaceNameAndNodePath(String nodePath) {
300 Matcher matcher = RenameConnector.FILE_EXPLORER_URL_SYNTAX.matcher(nodePath);
301 if (!matcher.find())
302 return null;
303 String[] workSpaceNameAndNodePath = new String[2];
304 workSpaceNameAndNodePath[0] = matcher.group(1);
305 workSpaceNameAndNodePath[1] = matcher.group(2);
306 return workSpaceNameAndNodePath;
307 }
308
309
310
311
312
313
314
315
316 private Session getSession(String workspaceName) throws Exception {
317 SessionProvider sessionProvider = WCMCoreUtils.getUserSessionProvider();
318 return sessionProvider.getSession(workspaceName, WCMCoreUtils.getRepository());
319 }
320 }