1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.services.cms.link.impl;
18
19 import java.security.AccessControlException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import javax.jcr.Item;
26 import javax.jcr.ItemNotFoundException;
27 import javax.jcr.Node;
28 import javax.jcr.NodeIterator;
29 import javax.jcr.PathNotFoundException;
30 import javax.jcr.RepositoryException;
31 import javax.jcr.Session;
32 import javax.jcr.ValueFormatException;
33 import javax.jcr.query.Query;
34 import javax.jcr.query.QueryManager;
35 import javax.jcr.query.QueryResult;
36
37 import org.exoplatform.services.cms.CmsService;
38 import org.exoplatform.services.cms.impl.Utils;
39 import org.exoplatform.services.cms.link.LinkManager;
40 import org.exoplatform.services.cms.link.NodeLinkAware;
41 import org.exoplatform.services.jcr.access.AccessControlEntry;
42 import org.exoplatform.services.jcr.access.PermissionType;
43 import org.exoplatform.services.jcr.core.ExtendedNode;
44 import org.exoplatform.services.jcr.core.ManageableRepository;
45 import org.exoplatform.services.jcr.ext.app.SessionProviderService;
46 import org.exoplatform.services.jcr.ext.common.SessionProvider;
47 import org.exoplatform.services.listener.ListenerService;
48 import org.exoplatform.services.log.ExoLogger;
49 import org.exoplatform.services.log.Log;
50 import org.exoplatform.services.security.IdentityConstants;
51 import org.exoplatform.services.wcm.core.NodetypeConstant;
52 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
53
54
55
56
57
58
59
60 public class LinkManagerImpl implements LinkManager {
61
62 private final static String SYMLINK = "exo:symlink";
63
64 private final static String WORKSPACE = "exo:workspace";
65
66 private final static String UUID = "exo:uuid";
67
68 private final static String PRIMARY_TYPE = "exo:primaryType";
69
70 private final static String SYMLINK_NAME = "exo:name";
71
72 private final static String SYMLINK_TITLE = "exo:title";
73
74 private final static Log LOG = ExoLogger.getLogger(LinkManagerImpl.class.getName());
75
76 private final SessionProviderService providerService_;
77
78 public LinkManagerImpl(SessionProviderService providerService) throws Exception {
79 providerService_ = providerService;
80 }
81
82
83
84
85 public Node createLink(Node parent, String linkType, Node target) throws RepositoryException {
86 return createLink(parent, linkType, target, null);
87 }
88
89
90
91
92 public Node createLink(Node parent, Node target) throws RepositoryException {
93 return createLink(parent, null, target, null);
94 }
95
96
97
98
99 public Node createLink(Node parent, String linkType, Node target, String linkName) throws RepositoryException {
100 return createLink(parent, linkType, target, linkName, linkName);
101 }
102
103
104
105
106 public Node createLink(Node parent, String linkType, Node target, String linkName, String linkTitle)
107 throws RepositoryException {
108 if (!target.isNodeType(SYMLINK)) {
109 boolean targetEdited = false;
110 if (target.canAddMixin("mix:referenceable")) {
111 target.addMixin("mix:referenceable");
112 target.getSession().save();
113 targetEdited = true;
114 }
115 if (linkType == null || linkType.trim().length() == 0)
116 linkType = SYMLINK;
117 if (linkName == null || linkName.trim().length() == 0)
118 linkName = target.getName();
119 Node linkNode = parent.addNode(linkName, linkType);
120 try {
121 updateAccessPermissionToLink(linkNode, target);
122 } catch(Exception e) {
123 if (LOG.isErrorEnabled()) {
124 LOG.error("CAN NOT UPDATE ACCESS PERMISSIONS FROM TARGET NODE TO LINK NODE", e);
125 }
126 }
127 linkNode.setProperty(WORKSPACE, target.getSession().getWorkspace().getName());
128 linkNode.setProperty(PRIMARY_TYPE, target.getPrimaryNodeType().getName());
129 linkNode.setProperty(UUID, target.getUUID());
130 if(linkNode.canAddMixin("exo:sortable")) {
131 linkNode.addMixin("exo:sortable");
132 }
133 linkNode.setProperty(SYMLINK_TITLE, linkTitle);
134 linkNode.setProperty(SYMLINK_NAME, linkName);
135 linkNode.getSession().save();
136 ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class);
137 try {
138 String remoteUser = WCMCoreUtils.getRemoteUser();
139 if (remoteUser != null) {
140 if (Utils.isDocument(target) && targetEdited) {
141 listenerService.broadcast(CmsService.POST_EDIT_CONTENT_EVENT, null, target);
142 }
143 }
144 } catch (Exception e) {
145 if (LOG.isErrorEnabled()) {
146 LOG.error("Error while broadcasting event: " + e.getMessage());
147 }
148 }
149 return linkNode;
150 }
151 return null;
152 }
153
154
155
156
157 public Node getTarget(Node link, boolean system) throws ItemNotFoundException,
158 RepositoryException {
159 String uuid = link.getProperty(UUID).getString();
160 Node targetNode = getSession(link, system).getNodeByUUID(uuid);
161 return targetNode;
162 }
163
164 private Session getSession(Node link, boolean system) throws RepositoryException {
165 String workspaceTarget = link.getProperty(WORKSPACE).getString();
166 return getSession((ManageableRepository) link.getSession().getRepository(), workspaceTarget,
167 system);
168 }
169
170 private Session getSession(ManageableRepository manageRepository, String workspaceName,
171 boolean system) throws RepositoryException {
172 if (system)
173 return providerService_.getSystemSessionProvider(null).getSession(workspaceName, manageRepository);
174 return providerService_.getSessionProvider(null).getSession(workspaceName, manageRepository);
175 }
176
177
178
179
180 public Node getTarget(Node link) throws ItemNotFoundException, RepositoryException {
181 return getTarget(link, false);
182 }
183
184
185
186
187 public boolean isTargetReachable(Node link) throws RepositoryException {
188 return isTargetReachable(link, false);
189 }
190
191
192
193
194 public boolean isTargetReachable(Node link, boolean system) throws RepositoryException {
195 Session session = null;
196 try {
197 session = getSession(link, system);
198 session.getNodeByUUID(link.getProperty(UUID).getString());
199 } catch (ItemNotFoundException e) {
200 return false;
201 }
202 return true;
203 }
204
205
206
207
208 public Node updateLink(Node linkNode, Node targetNode) throws RepositoryException {
209 if (targetNode.canAddMixin("mix:referenceable")) {
210 targetNode.addMixin("mix:referenceable");
211 targetNode.getSession().save();
212 }
213 try {
214 updateAccessPermissionToLink(linkNode, targetNode);
215 } catch(Exception e) {
216 if (LOG.isErrorEnabled()) {
217 LOG.error("CAN NOT UPDATE ACCESS PERMISSIONS FROM TARGET NODE TO LINK NODE", e);
218 }
219 }
220 linkNode.setProperty(UUID, targetNode.getUUID());
221 linkNode.setProperty(PRIMARY_TYPE, targetNode.getPrimaryNodeType().getName());
222 linkNode.setProperty(WORKSPACE, targetNode.getSession().getWorkspace().getName());
223 linkNode.getSession().save();
224 return linkNode;
225 }
226
227
228
229
230 public boolean isLink(Item item) throws RepositoryException {
231 if (item instanceof Node) {
232 Node node = (Node) item;
233 if (node instanceof NodeLinkAware) {
234 node = ((NodeLinkAware) node).getRealNode();
235 }
236 return node.isNodeType(SYMLINK);
237 }
238 return false;
239 }
240
241
242
243
244 public String getTargetPrimaryNodeType(Node link) throws RepositoryException {
245 return link.getProperty(PRIMARY_TYPE).getString();
246 }
247
248
249
250
251
252
253
254 private void updateAccessPermissionToLink(Node linkNode, Node targetNode) throws Exception {
255 if(canChangePermission(linkNode)) {
256 if(linkNode.canAddMixin("exo:privilegeable")) {
257 linkNode.addMixin("exo:privilegeable");
258 ((ExtendedNode)linkNode).setPermission(getNodeOwner(linkNode),PermissionType.ALL);
259 }
260 removeCurrentIdentites(linkNode);
261 Map<String, String[]> perMap = new HashMap<String, String[]>();
262 List<String> permsList = new ArrayList<String>();
263 List<String> idList = new ArrayList<String>();
264 for(AccessControlEntry accessEntry : ((ExtendedNode)targetNode).getACL().getPermissionEntries()) {
265 if(!idList.contains(accessEntry.getIdentity())) {
266 idList.add(accessEntry.getIdentity());
267 permsList = ((ExtendedNode)targetNode).getACL().getPermissions(accessEntry.getIdentity());
268 perMap.put(accessEntry.getIdentity(), permsList.toArray(new String[permsList.size()]));
269 }
270 }
271 ((ExtendedNode)linkNode).setPermissions(perMap);
272 }
273 }
274
275
276
277
278
279
280
281 private void removeCurrentIdentites(Node linkNode) throws AccessControlException, RepositoryException {
282 String currentUser = linkNode.getSession().getUserID();
283 if (currentUser != null)
284 ((ExtendedNode)linkNode).setPermission(currentUser, PermissionType.ALL);
285 for(AccessControlEntry accessEntry : ((ExtendedNode)linkNode).getACL().getPermissionEntries()) {
286 if(canRemovePermission(linkNode, accessEntry.getIdentity())
287 && ((ExtendedNode)linkNode).getACL().getPermissions(accessEntry.getIdentity()).size() > 0
288 && !accessEntry.getIdentity().equals(currentUser)) {
289 ((ExtendedNode) linkNode).removePermission(accessEntry.getIdentity());
290 }
291 }
292 }
293
294
295
296
297
298
299
300
301
302
303 private boolean canRemovePermission(Node node, String identity) throws ValueFormatException,
304 PathNotFoundException, RepositoryException {
305 String owner = getNodeOwner(node);
306 if(identity.equals(IdentityConstants.SYSTEM)) return false;
307 if(owner != null && owner.equals(identity)) return false;
308 return true;
309 }
310
311
312
313
314
315
316
317
318
319 private String getNodeOwner(Node node) throws ValueFormatException, PathNotFoundException, RepositoryException {
320 if(node.hasProperty("exo:owner")) {
321 return node.getProperty("exo:owner").getString();
322 }
323 return IdentityConstants.SYSTEM;
324 }
325
326
327
328
329
330
331
332 private boolean canChangePermission(Node node) throws RepositoryException {
333 try {
334 ((ExtendedNode)node).checkPermission(PermissionType.CHANGE_PERMISSION);
335 return true;
336 } catch(AccessControlException e) {
337 return false;
338 }
339 }
340
341
342
343
344 public List<Node> getAllLinks(Node targetNode, String linkType, SessionProvider sessionProvider) {
345 try {
346 List<Node> result = new ArrayList<Node>();
347 ManageableRepository repository = WCMCoreUtils.getRepository();
348 String[] workspaces = repository.getWorkspaceNames();
349 String queryString = new StringBuilder().append("SELECT * FROM ").
350 append(linkType).
351 append(" WHERE exo:uuid='").
352 append(targetNode.getUUID()).append("'").
353 append(" AND exo:workspace='").
354 append(targetNode.getSession().getWorkspace().getName()).
355 append("'").toString();
356
357 for (String workspace : workspaces) {
358 Session session = sessionProvider.getSession(workspace, repository);
359
360 if(session == null) continue;
361 QueryManager queryManager = session.getWorkspace().getQueryManager();
362 Query query = queryManager.createQuery(queryString, Query.SQL);
363 QueryResult queryResult = query.execute();
364 NodeIterator iter = queryResult.getNodes();
365 while (iter.hasNext()) {
366 result.add(iter.nextNode());
367 }
368 }
369
370 return result;
371 } catch (RepositoryException e) {
372
373 return new ArrayList<Node>();
374 }
375 }
376
377
378
379
380 public List<Node> getAllLinks(Node targetNode, String linkType) {
381 return getAllLinks(targetNode, linkType, WCMCoreUtils.getUserSessionProvider());
382 }
383
384
385
386
387
388 public void updateSymlink(Node node) throws RepositoryException {
389 if (node.isNodeType(NodetypeConstant.EXO_SYMLINK)) {
390 try {
391 ((ExtendedNode)node).checkPermission(PermissionType.SET_PROPERTY);
392 } catch(AccessControlException e) {
393 SessionProvider provider = WCMCoreUtils.getSystemSessionProvider();
394 node = (Node)provider.getSession(node.getSession().getWorkspace().getName(),
395 WCMCoreUtils.getRepository()).getItem(node.getPath());
396 }
397 if (node.canAddMixin(NodetypeConstant.EXO_TARGET_DATA)) {
398 node.addMixin(NodetypeConstant.EXO_TARGET_DATA);
399 }
400 Node target = this.getTarget(node, true);
401 if (!node.hasProperty(NodetypeConstant.EXO_LAST_MODIFIED_DATE) ||
402 node.getProperty(NodetypeConstant.EXO_LAST_MODIFIED_DATE).getDate().compareTo(
403 target.getProperty(NodetypeConstant.EXO_LAST_MODIFIED_DATE).getDate()) < 0) {
404 String[] propList = {NodetypeConstant.EXO_DATE_CREATED,
405 NodetypeConstant.EXO_LAST_MODIFIED_DATE, NodetypeConstant.PUBLICATION_LIVE_DATE,
406 NodetypeConstant.EXO_START_EVENT, NodetypeConstant.EXO_INDEX};
407 for (String p : propList) {
408 try {
409 if (target.hasProperty(p)) {
410 node.setProperty(p, target.getProperty(p).getValue());
411 node.save();
412 }
413 } catch (RepositoryException e) {
414 if (LOG.isErrorEnabled()) {
415 LOG.error("Can not update property: " + p + " for node: " + node.getPath(), e);
416 }
417 }
418 }
419 }
420 }
421 }
422
423 }