View Javadoc

1   /**
2    * This file Copyright (c) 2013 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.cms.core.MgnlNodeType;
37  import info.magnolia.jcr.decoration.AbstractContentDecorator;
38  
39  import java.util.LinkedHashMap;
40  import java.util.LinkedList;
41  import java.util.Map;
42  
43  import javax.jcr.Node;
44  import javax.jcr.Property;
45  import javax.jcr.RepositoryException;
46  import javax.jcr.Session;
47  import javax.jcr.Workspace;
48  import javax.jcr.nodetype.NodeType;
49  
50  /**
51   * Magnolia audit logging content decorator for use by node, property and session wrapper classes.
52   */
53  public class MgnlAuditLoggingContentDecorator extends AbstractContentDecorator {
54  
55      /**
56       * Map where we store each log entry, before it is logged into audit-log output during save action.
57       */
58      private Map<String, LinkedList<MgnlAuditLogEntry>> logEntries = new LinkedHashMap<String, LinkedList<MgnlAuditLogEntry>>();
59  
60      /**
61       * Get map which contains audit-log entries of actions (Create, Modify, Delete, Move)
62       * which were done in this session and were not yet saved.
63       * 
64       * @return map of audit-log entries
65       */
66      public Map<String, LinkedList<MgnlAuditLogEntry>> getLogEntries() {
67          return logEntries;
68      }
69  
70      /**
71       * Wrap session by Magnolia audit logging session wrapper.
72       */
73      @Override
74      public Session wrapSession(Session session) {
75          return new MgnlAuditLoggingContentDecoratorSessionWrapper(session, this);
76      }
77  
78      /**
79       * Wrap node by Magnolia audit logging node wrapper.
80       */
81      @Override
82      public Node wrapNode(Node node) {
83          return new MgnlAuditLoggingContentDecoratorNodeWrapper(node, this);
84      }
85  
86      /**
87       * Wrap property by Magnolia audit logging property wrapper.
88       */
89      @Override
90      public Property wrapProperty(Property property) {
91          return new MgnlAuditLoggingContentDecoratorPropertyWrapper(property, this);
92      }
93  
94      /**
95       * Wrap workspace by Magnolia audit logging workspace wrapper.
96       */
97      @Override
98      public Workspace wrapWorkspace(Workspace workspace) {
99          return new MgnlAuditLoggingContentDecoratorWorspaceWrapper(workspace, this);
100     }
101 
102     @Override
103     public boolean isMultipleWrapEnabled() {
104         return false;
105     }
106 
107     /**
108      * Method which take care of storing creation of node into audit-log entries map.
109      */
110     protected void logActionCreate(Node node) throws RepositoryException {
111         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
112         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
113             return;
114         }
115 
116         final long timeStamp = System.nanoTime();
117         logActionCreate(node.getPath(), node.getSession().getWorkspace().getName(), node.getPrimaryNodeType(), timeStamp);
118     }
119 
120     /**
121      * Method which take care of storing creation of node into audit-log entries map.
122      */
123     protected void logActionCreate(String path, String workspace, NodeType nodeType, long timeStamp) {
124         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
125         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
126             return;
127         }
128 
129         if (!logEntries.containsKey(path)) {
130             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_CREATE, workspace, nodeType, path, timeStamp);
131             addPathFirstLogEntry(path, entry);
132         } else {
133             // this should happen only if last action is MOVE or DELETE
134             logEntries.get(path).add(createLogEntry(AuditLoggingUtil.ACTION_CREATE, workspace, nodeType, path, timeStamp));
135         }
136     }
137 
138     /**
139      * Method which take care of storing modification action into audit-log entries map.
140      * Modification of node's MetaData store like modification of the node.
141      */
142     protected void logActionModify(Node node) throws RepositoryException {
143         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
144         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
145             return;
146         }
147 
148         final long timeStamp = System.nanoTime();
149         if (node.isNodeType(MgnlNodeType.NT_METADATA)) {
150             node = node.getParent();
151         }
152         logActionModify(node.getPath(), node.getSession().getWorkspace().getName(), node.getPrimaryNodeType(), timeStamp);
153     }
154 
155     /**
156      * Method which take care of storing modification action into audit-log entries map.
157      */
158     protected void logActionModify(String path, String workspace, NodeType nodeType, final long timeStamp) {
159         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
160         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
161             return;
162         }
163 
164         if (!logEntries.containsKey(path)) {
165             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_MODIFY, workspace, nodeType, path, timeStamp);
166             addPathFirstLogEntry(path, entry);
167         } else {
168             // if last logged action is CREATE or MODIFY don't log this action
169             LinkedList<MgnlAuditLogEntry> pathEntries = logEntries.get(path);
170             final String lastAction = pathEntries.getLast().getAction();
171             if (lastAction.equals(AuditLoggingUtil.ACTION_CREATE) || lastAction.equals(AuditLoggingUtil.ACTION_MODIFY)) {
172                 return;
173             }
174             pathEntries.add(createLogEntry(AuditLoggingUtil.ACTION_MODIFY, workspace, nodeType, path, timeStamp));
175         }
176     }
177 
178     /**
179      * Method which take care of storing move action into audit-log entries map.
180      */
181     public void logActionMove(String srcAbsPath, String destAbsPath, String workspace) {
182         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
183         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
184             return;
185         }
186 
187         final long timeStamp = System.nanoTime();
188         if (!logEntries.containsKey(srcAbsPath)) {
189             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_MOVE, workspace, srcAbsPath, destAbsPath, timeStamp);
190             addPathFirstLogEntry(srcAbsPath, entry);
191         } else {
192             logEntries.get(srcAbsPath).add(createLogEntry(AuditLoggingUtil.ACTION_MOVE, workspace, srcAbsPath, destAbsPath, timeStamp));
193         }
194     }
195 
196     /**
197      * Method which take care of storing delete action into audit-log entries map.
198      */
199     protected void logActionDelete(String path, String workspace, NodeType nodeType) {
200         AuditLoggingManager auditLoggingManager = AuditLoggingManager.getInstance();
201         if (auditLoggingManager == null || !auditLoggingManager.isAuditLoggingActive()) {
202             return;
203         }
204 
205         final long timeStamp = System.nanoTime();
206         if (!logEntries.containsKey(path)) {
207             MgnlAuditLogEntry entry = createLogEntry(AuditLoggingUtil.ACTION_DELETE, workspace, nodeType, path, timeStamp);
208             addPathFirstLogEntry(path, entry);
209         } else {
210             LinkedList<MgnlAuditLogEntry> pathEntries = logEntries.get(path);
211             MgnlAuditLogEntry lastPathEntry = pathEntries.getLast();
212             final String lastAction = lastPathEntry.getAction();
213             if (lastAction.equals(AuditLoggingUtil.ACTION_CREATE)) {
214                 // if last logged action is CREATE than remove it from log and don't log delete
215                 pathEntries.remove(lastPathEntry);
216                 return;
217             } else if (lastAction.equals(AuditLoggingUtil.ACTION_MODIFY)) {
218                 // if last logged action is MODIFY than remove it from log and log delete
219                 pathEntries.remove(lastPathEntry);
220                 pathEntries.add(createLogEntry(AuditLoggingUtil.ACTION_DELETE, workspace, nodeType, path, timeStamp));
221                 return;
222             }
223             pathEntries.add(createLogEntry(AuditLoggingUtil.ACTION_DELETE, workspace, nodeType, path, timeStamp));
224         }
225     }
226 
227     private void addPathFirstLogEntry(String path, MgnlAuditLogEntry entry) {
228         LinkedList<MgnlAuditLogEntry> pathEntries = new LinkedList<MgnlAuditLogEntry>();
229         pathEntries.add(entry);
230         logEntries.put(path, pathEntries);
231     }
232 
233     /**
234      * Create audit-log entry for move action.
235      */
236     private MgnlAuditLogEntry createLogEntry(String action, String workspace, String pathFrom, String pathTo, long timeStamp) {
237         return new MgnlAuditLogEntry(action, workspace, pathFrom, pathTo, timeStamp);
238     }
239 
240     /**
241      * Create audit-log entry for create, modify and delete action.
242      */
243     private MgnlAuditLogEntry createLogEntry(String action, String workspace, NodeType nodeType, String path, long timeStamp) {
244         return new MgnlAuditLogEntry(action, workspace, nodeType, path, timeStamp);
245     }
246 
247 }