View Javadoc
1   /**
2    * This file Copyright (c) 2013-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.audit;
35  
36  import info.magnolia.jcr.decoration.AbstractContentDecorator;
37  
38  import java.util.LinkedHashMap;
39  import java.util.LinkedList;
40  import java.util.Map;
41  
42  import javax.jcr.Node;
43  import javax.jcr.Property;
44  import javax.jcr.RepositoryException;
45  import javax.jcr.Session;
46  import javax.jcr.Workspace;
47  import javax.jcr.nodetype.NodeType;
48  
49  /**
50   * Magnolia audit logging content decorator for use by node, property and session wrapper classes.
51   */
52  public class MgnlAuditLoggingContentDecorator extends AbstractContentDecorator {
53  
54      /**
55       * Map where we store each log entry, before it is logged into audit-log output during save action.
56       */
57      private Map<String, LinkedList<MgnlAuditLogEntry>> logEntries = new LinkedHashMap<String, LinkedList<MgnlAuditLogEntry>>();
58  
59      /**
60       * Get map which contains audit-log entries of actions (Create, Modify, Delete, Move)
61       * which were done in this session and were not yet saved.
62       *
63       * @return map of audit-log entries
64       */
65      public Map<String, LinkedList<MgnlAuditLogEntry>> getLogEntries() {
66          return logEntries;
67      }
68  
69      /**
70       * Wrap session by Magnolia audit logging session wrapper.
71       */
72      @Override
73      public Session wrapSession(Session session) {
74          return new MgnlAuditLoggingContentDecoratorSessionWrapper(session, this);
75      }
76  
77      /**
78       * Wrap node by Magnolia audit logging node wrapper.
79       */
80      @Override
81      public Node wrapNode(Node node) {
82          return new MgnlAuditLoggingContentDecoratorNodeWrapper(node, this);
83      }
84  
85      /**
86       * Wrap property by Magnolia audit logging property wrapper.
87       */
88      @Override
89      public Property wrapProperty(Property property) {
90          return new MgnlAuditLoggingContentDecoratorPropertyWrapper(property, this);
91      }
92  
93      /**
94       * Wrap workspace by Magnolia audit logging workspace wrapper.
95       */
96      @Override
97      public Workspace wrapWorkspace(Workspace workspace) {
98          return new MgnlAuditLoggingContentDecoratorWorspaceWrapper(workspace, this);
99      }
100 
101     @Override
102     public boolean isMultipleWrapEnabled() {
103         return false;
104     }
105 
106     /**
107      * Method which take care of storing creation of node into audit-log entries map.
108      */
109     protected void logActionCreate(Node node) throws RepositoryException {
110         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
111         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
112             return;
113         }
114 
115         final long timeStamp = System.nanoTime();
116         logActionCreate(node.getPath(), node.getSession().getWorkspace().getName(), node.getPrimaryNodeType(), timeStamp);
117     }
118 
119     /**
120      * Method which take care of storing creation of node into audit-log entries map.
121      */
122     protected void logActionCreate(String path, String workspace, NodeType nodeType, long timeStamp) {
123         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
124         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
125             return;
126         }
127 
128         if (!logEntries.containsKey(path)) {
129             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_CREATE, workspace, nodeType, path, timeStamp);
130             addPathFirstLogEntry(path, entry);
131         } else {
132             // this should happen only if last action is MOVE or DELETE
133             logEntries.get(path).add(createLogEntry(AuditLoggingUtil.ACTION_CREATE, workspace, nodeType, path, timeStamp));
134         }
135     }
136 
137     /**
138      * Method which take care of storing modification action into audit-log entries map.
139      */
140     protected void logActionModify(Node node) throws RepositoryException {
141         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
142         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
143             return;
144         }
145 
146         final long timeStamp = System.nanoTime();
147         logActionModify(node.getPath(), node.getSession().getWorkspace().getName(), node.getPrimaryNodeType(), timeStamp);
148     }
149 
150     /**
151      * Method which take care of storing modification action into audit-log entries map.
152      */
153     protected void logActionModify(String path, String workspace, NodeType nodeType, final long timeStamp) {
154         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
155         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
156             return;
157         }
158 
159         if (!logEntries.containsKey(path)) {
160             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_MODIFY, workspace, nodeType, path, timeStamp);
161             addPathFirstLogEntry(path, entry);
162         } else {
163             // if last logged action is CREATE or MODIFY don't log this action
164             LinkedList<MgnlAuditLogEntry> pathEntries = logEntries.get(path);
165             if (!pathEntries.isEmpty()) {
166                 final String lastAction = pathEntries.getLast().getAction();
167                 if (lastAction.equals(AuditLoggingUtil.ACTION_CREATE) || lastAction.equals(AuditLoggingUtil.ACTION_MODIFY)) {
168                     return;
169                 }
170             }
171             pathEntries.add(createLogEntry(AuditLoggingUtil.ACTION_MODIFY, workspace, nodeType, path, timeStamp));
172         }
173     }
174 
175     /**
176      * Method which take care of storing move action into audit-log entries map.
177      */
178     public void logActionMove(String srcAbsPath, String destAbsPath, String workspace) {
179         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
180         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
181             return;
182         }
183 
184         final long timeStamp = System.nanoTime();
185         if (!logEntries.containsKey(srcAbsPath)) {
186             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_MOVE, workspace, srcAbsPath, destAbsPath, timeStamp);
187             addPathFirstLogEntry(srcAbsPath, entry);
188         } else {
189             logEntries.get(srcAbsPath).add(createLogEntry(AuditLoggingUtil.ACTION_MOVE, workspace, srcAbsPath, destAbsPath, timeStamp));
190         }
191     }
192 
193     /**
194      * Method which take care of storing delete action into audit-log entries map.
195      */
196     protected void logActionDelete(String path, String workspace, NodeType nodeType) {
197         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
198         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
199             return;
200         }
201 
202         final long timeStamp = System.nanoTime();
203         if (!logEntries.containsKey(path)) {
204             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_DELETE, workspace, nodeType, path, timeStamp);
205             addPathFirstLogEntry(path, entry);
206         } else {
207             LinkedList<MgnlAuditLogEntry> pathEntries = logEntries.get(path);
208             if (!pathEntries.isEmpty()) {
209                 MgnlAuditLogEntry lastPathEntry = pathEntries.getLast();
210                 final String lastAction = lastPathEntry.getAction();
211                 if (lastAction.equals(AuditLoggingUtil.ACTION_CREATE)) {
212                     // if last logged action is CREATE than remove it from log and don't log delete
213                     pathEntries.remove(lastPathEntry);
214                     return;
215                 } else if (lastAction.equals(AuditLoggingUtil.ACTION_MODIFY)) {
216                     // if last logged action is MODIFY than remove it from log and log delete
217                     pathEntries.remove(lastPathEntry);
218                     pathEntries.add(createLogEntry(AuditLoggingUtil.ACTION_DELETE, workspace, nodeType, path, timeStamp));
219                     return;
220                 }
221             }
222             pathEntries.add(createLogEntry(AuditLoggingUtil.ACTION_DELETE, workspace, nodeType, path, timeStamp));
223         }
224     }
225 
226     private void addPathFirstLogEntry(String path, MgnlAuditLogEntry entry) {
227         LinkedList<MgnlAuditLogEntry> pathEntries = new LinkedList<MgnlAuditLogEntry>();
228         pathEntries.add(entry);
229         logEntries.put(path, pathEntries);
230     }
231 
232     /**
233      * Create audit-log entry for move action.
234      */
235     private MgnlAuditLogEntry createLogEntry(String action, String workspace, String pathFrom, String pathTo, long timeStamp) {
236         return new MgnlAuditLogEntry(action, workspace, pathFrom, pathTo, timeStamp);
237     }
238 
239     /**
240      * Create audit-log entry for create, modify and delete action.
241      */
242     private MgnlAuditLogEntry createLogEntry(String action, String workspace, NodeType nodeType, String path, long timeStamp) {
243         return new MgnlAuditLogEntry(action, workspace, nodeType, path, timeStamp);
244     }
245 
246 }