View Javadoc
1   package org.exoplatform.services.wcm.search.connector;
2   
3   import org.apache.commons.chain.Context;
4   import org.exoplatform.commons.search.index.IndexingService;
5   import org.exoplatform.commons.utils.CommonsUtils;
6   import org.exoplatform.services.cms.documents.TrashService;
7   import org.exoplatform.services.ext.action.InvocationContext;
8   import org.exoplatform.services.jcr.impl.core.NodeImpl;
9   import org.exoplatform.services.jcr.impl.core.PropertyImpl;
10  import org.exoplatform.services.jcr.impl.ext.action.AdvancedAction;
11  import org.exoplatform.services.jcr.impl.ext.action.AdvancedActionException;
12  import org.exoplatform.services.jcr.observation.ExtendedEvent;
13  import org.exoplatform.services.log.ExoLogger;
14  import org.exoplatform.services.log.Log;
15  import org.exoplatform.services.wcm.core.NodeLocation;
16  import org.exoplatform.services.wcm.core.NodetypeConstant;
17  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
18  
19  import javax.jcr.Node;
20  import javax.jcr.NodeIterator;
21  import javax.jcr.RepositoryException;
22  import javax.jcr.observation.Event;
23  import java.util.function.Consumer;
24  import java.util.function.Predicate;
25  
26  /**
27   *  JCR action which listens on all nodes events to index them
28   */
29  public class FileIndexerAction implements AdvancedAction {
30    private static final Log LOGGER = ExoLogger.getExoLogger(FileIndexerAction.class);
31  
32    private IndexingService indexingService;
33  
34    private TrashService trashService;
35  
36    public FileIndexerAction() {
37      this.indexingService = CommonsUtils.getService(IndexingService.class);
38      this.trashService = CommonsUtils.getService(TrashService.class);
39    }
40  
41    @Override
42    public boolean execute(Context context) throws Exception {
43      NodeImpl node;
44  
45      int eventType = (Integer) context.get(InvocationContext.EVENT);
46  
47      switch(eventType) {
48        case Event.NODE_ADDED:
49          node = (NodeImpl)context.get(InvocationContext.CURRENT_ITEM);
50          if(node != null) {
51            if (trashService.isInTrash(node)) {
52              applyIndexingOperationOnNodes(node, n -> indexingService.unindex(FileindexingConnector.TYPE, n.getInternalIdentifier()), n -> true);
53            } else {
54              applyIndexingOperationOnNodes(node, n -> indexingService.index(FileindexingConnector.TYPE, n.getInternalIdentifier()), n -> true);
55            }
56          }
57          break;
58        case Event.NODE_REMOVED:
59          node = (NodeImpl)context.get(InvocationContext.CURRENT_ITEM);
60          if(node != null) {
61            applyIndexingOperationOnNodes(node, n -> indexingService.unindex(FileindexingConnector.TYPE, n.getInternalIdentifier()), n -> true);
62          }
63          break;
64        case Event.PROPERTY_ADDED:
65        case Event.PROPERTY_CHANGED:
66        case Event.PROPERTY_REMOVED:
67          PropertyImpl property = (PropertyImpl) context.get(InvocationContext.CURRENT_ITEM);
68          if(property != null) {
69            node = property.getParent();
70            if (node != null && !trashService.isInTrash(node)) {
71              if (node.isNodeType(NodetypeConstant.NT_RESOURCE)) {
72                node = node.getParent();
73              }
74              if (node.isNodeType(NodetypeConstant.NT_FILE)) {
75                indexingService.reindex(FileindexingConnector.TYPE, node.getInternalIdentifier());
76              }
77            }
78          }
79          break;
80        case ExtendedEvent.PERMISSION_CHANGED:
81          node = (NodeImpl)context.get(InvocationContext.CURRENT_ITEM);
82          if (node != null && !trashService.isInTrash(node)) {
83            // reindex children nodes when permissions has been changed (exo:permissions) - it is required
84            // to update permissions of the nodes in the indexing engine
85            applyIndexingOperationOnNodes(node, n -> indexingService.reindex(FileindexingConnector.TYPE, n.getInternalIdentifier()), n -> hasNotPrivilegeableMixin(n));
86          }
87          break;
88      }
89  
90      return true;
91    }
92  
93    @Override
94    public void onError(Exception e, Context context) throws AdvancedActionException {
95      LOGGER.error("Error while indexing file", e);
96    }
97  
98    protected Node getNodeByPath(String path) {
99      return NodeLocation.getNodeByLocation(new NodeLocation(WCMCoreUtils.getRepository().getConfiguration().getName(), "collaboration", path));
100   }
101 
102   /**
103    * Apply the given indexing operation (index|reindex|unindex) on all children of a node, only for nt:file nodes
104    * @param node The root node to operate on
105    * @param filter skip process node if filter return true
106    * @param indexingOperation Indexing operation (index|reindex|unindex) to apply on the nodes
107    */
108   protected void applyIndexingOperationOnNodes(NodeImpl node, Consumer<NodeImpl> indexingOperation, Predicate<NodeImpl> filter) {
109     if (node == null) {
110       return;
111     }
112 
113     try {
114       if (node.isNodeType(NodetypeConstant.NT_FILE)) {
115         indexingOperation.accept(node);
116       }
117     } catch (RepositoryException e) {
118       LOGGER.error("Cannot get primary type of node " + node.getInternalIdentifier(), e);
119     }
120 
121     try {
122       NodeIterator nodeIterator = node.getNodes();
123       while(nodeIterator.hasNext()) {
124         NodeImpl childNode = (NodeImpl) nodeIterator.nextNode();
125         if(! filter.test(childNode))
126           continue;
127         applyIndexingOperationOnNodes(childNode, indexingOperation, filter);
128       }
129     } catch (RepositoryException e) {
130       LOGGER.error("Cannot get child nodes of node " + node.getInternalIdentifier(), e);
131     }
132   }
133   // Check if the node has exo:privilegeable mixin
134   private boolean hasNotPrivilegeableMixin(NodeImpl node) {
135     try {
136       return ! node.isNodeType(NodetypeConstant.EXO_PRIVILEGEABLE);
137     } catch (RepositoryException e) {
138       LOGGER.error("Error while check privilegeable mixin ", e);
139     }
140     return true;
141   }
142 }