1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.admininterface.lists;
35
36 import info.magnolia.cms.beans.config.VersionConfig;
37 import info.magnolia.cms.core.Content;
38 import info.magnolia.cms.core.HierarchyManager;
39 import info.magnolia.cms.core.MetaData;
40 import info.magnolia.cms.gui.control.ContextMenu;
41 import info.magnolia.cms.gui.control.ContextMenuItem;
42 import info.magnolia.cms.gui.control.FunctionBar;
43 import info.magnolia.cms.gui.control.FunctionBarItem;
44 import info.magnolia.cms.gui.controlx.list.ListColumn;
45 import info.magnolia.cms.gui.controlx.list.ListControl;
46 import info.magnolia.cms.gui.controlx.list.ListModel;
47 import info.magnolia.cms.gui.controlx.version.VersionListModel;
48 import info.magnolia.cms.i18n.MessagesManager;
49 import info.magnolia.cms.security.AccessDeniedException;
50 import info.magnolia.cms.util.AlertUtil;
51 import info.magnolia.cms.util.ExclusiveWrite;
52 import info.magnolia.context.Context;
53 import info.magnolia.context.MgnlContext;
54 import info.magnolia.context.SystemContext;
55 import info.magnolia.freemarker.FreemarkerUtil;
56 import info.magnolia.module.admininterface.VersionUtil;
57 import info.magnolia.objectfactory.Components;
58
59 import java.util.Collection;
60
61 import javax.jcr.InvalidItemStateException;
62 import javax.jcr.LoginException;
63 import javax.jcr.Node;
64 import javax.jcr.PathNotFoundException;
65 import javax.jcr.RepositoryException;
66 import javax.jcr.Session;
67 import javax.jcr.UnsupportedRepositoryOperationException;
68 import javax.jcr.version.Version;
69 import javax.servlet.http.HttpServletRequest;
70 import javax.servlet.http.HttpServletResponse;
71
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75
76
77
78
79
80 public abstract class VersionsList extends AbstractList {
81
82 private static Logger log = LoggerFactory.getLogger(VersionsList.class);
83
84
85
86
87 private String repository;
88
89
90
91
92 protected String path;
93
94
95
96
97 private String versionLabel;
98
99 private String jsExecutedAfterSaving;
100
101
102
103
104
105
106
107 public VersionsList(String name, HttpServletRequest request, HttpServletResponse response) throws Exception {
108 super(name, request, response);
109 }
110
111
112
113
114 @Override
115 public ListModel getModel() {
116 try {
117 Content node = getNode();
118 return new VersionListModel(node, this.getMaxShowedVersions());
119 }
120 catch (Exception e) {
121 log.error("can't find node for version list {}", this.path);
122 }
123 return null;
124 }
125
126
127
128
129 protected int getMaxShowedVersions() {
130 return Math.min((int)VersionConfig.getInstance().getMaxVersionAllowed(), 50);
131 }
132
133 @Override
134 public void configureList(ListControl list) {
135
136 list.setRenderer(new AdminListControlRenderer() {
137 @Override
138 public String onDblClick(ListControl list, Integer index) {
139 return list.getName() + ".showItem()";
140 }
141
142 @Override
143 public String getJavaScriptClass() {
144 return "mgnl.admininterface.VersionsList";
145 }
146
147 @Override
148 protected String buildJavaScriptObject(ListControl list, Object value) {
149 return super.buildJavaScriptObject(list, value) + ", versionLabel: '" + list.getIteratorValue("versionLabel") + "'";
150 }
151
152 @Override
153 public String getConstructorArguments(ListControl list) {
154 return super.getConstructorArguments(list) + ", '"+repository+"', '"+path+"', " + getOnShowFunction() + ", " + getOnDiffFunction() ;
155 }
156
157 });
158
159 list.addGroupableField("userName");
160 list.addSortableField("created");
161 list.addColumn(new ListColumn("name", "Name", "150", true));
162 list.addColumn(new ListColumn("created", "Date", "100", true));
163 list.addColumn(new ListColumn("userName", "User", "100", true));
164 list.addColumn(new ListColumn("comment", "Comment", "150", true));
165 }
166
167
168
169
170 public abstract String getOnShowFunction();
171
172 @Override
173 protected void configureContextMenu(ContextMenu menu) {
174 ContextMenuItem show = new ContextMenuItem("show");
175 show.setLabel(MessagesManager.get("versions.show"));
176 show.setOnclick(this.getList().getName() + ".showItem()");
177 show.setIcon(MgnlContext.getContextPath() + "/.resources/icons/16/note_view.gif");
178 show.addJavascriptCondition("function(){return " + getList().getName()+".isSelected()}");
179
180 ContextMenuItem restore = new ContextMenuItem("restore");
181 restore.setLabel(MessagesManager.get("versions.restore"));
182 restore.setOnclick(this.getList().getName() + ".restore()");
183 restore.setIcon(MgnlContext.getContextPath() + "/.resources/icons/16/undo.gif");
184 restore.addJavascriptCondition("function(){return " + getList().getName()+".isSelected()}");
185
186 menu.addMenuItem(show);
187 menu.addMenuItem(restore);
188
189 if(isSupportsDiff()){
190 ContextMenuItem diffWithCurrent = new ContextMenuItem("diffWithCurrent");
191 diffWithCurrent.setLabel(MessagesManager.get("versions.compareWithCurrent"));
192 diffWithCurrent.setOnclick(this.getList().getName() + ".diffItemWithCurrent()");
193 diffWithCurrent.setIcon(MgnlContext.getContextPath() + "/.resources/icons/16/compare_with_current.gif");
194 diffWithCurrent.addJavascriptCondition("function(){return " + getList().getName()+".isSelected()}");
195
196 ContextMenuItem diffWithPrevious = new ContextMenuItem("diffWithPrevious");
197 diffWithPrevious.setLabel(MessagesManager.get("versions.compareWithPrevious"));
198 diffWithPrevious.setOnclick(this.getList().getName() + ".diffItemWithPrevious()");
199 diffWithPrevious.setIcon(MgnlContext.getContextPath() + "/.resources/icons/16/compare_with_previous.gif");
200 diffWithPrevious.addJavascriptCondition("function(){return " + getList().getName()+".hasPreviousVersion()}");
201
202 menu.addMenuItem(diffWithCurrent);
203 menu.addMenuItem(diffWithPrevious);
204 }
205 }
206
207 protected boolean isSupportsDiff() {
208 return false;
209 }
210
211
212
213
214 @Override
215 protected void configureFunctionBar(FunctionBar bar) {
216 bar.addMenuItem(new FunctionBarItem(this.getContextMenu().getMenuItemByName("show")));
217 bar.addMenuItem(new FunctionBarItem(this.getContextMenu().getMenuItemByName("restore")));
218
219 if(isSupportsDiff()){
220 bar.addMenuItem(new FunctionBarItem(this.getContextMenu().getMenuItemByName("diffWithCurrent")));
221 bar.addMenuItem(new FunctionBarItem(this.getContextMenu().getMenuItemByName("diffWithPrevious")));
222 }
223 }
224
225
226
227
228
229
230
231
232 protected Content getNode() throws PathNotFoundException, RepositoryException, AccessDeniedException {
233 HierarchyManager hm = MgnlContext.getHierarchyManager(this.getRepository());
234 Content node = hm.getContent(this.getPath());
235 return node;
236 }
237
238 protected Node getJCRNode() throws RepositoryException {
239 Session session = MgnlContext.getJCRSession(this.getRepository());
240 return session.getNode(this.getPath());
241 }
242
243 protected void addComment(final Content node, String version) throws AccessDeniedException, RepositoryException {
244 synchronized (ExclusiveWrite.getInstance()) {
245 node.getMetaData().setProperty(Context.ATTRIBUTE_COMMENT, MessagesManager.get("versions.comment.restore"));
246 node.save();
247 }
248 }
249
250 protected void cleanComment(final Content node) throws AccessDeniedException, RepositoryException {
251 synchronized (ExclusiveWrite.getInstance()) {
252 MetaData md = node.getMetaData();
253 if(md.hasProperty(Context.ATTRIBUTE_COMMENT)){
254 md.removeProperty(Context.ATTRIBUTE_COMMENT);
255 node.save();
256 }
257 }
258 }
259
260 public String restore() {
261 try {
262 final Content node = this.getNode();
263 final String version = this.getVersionLabel();
264 addComment(node, version);
265 node.addVersion();
266 cleanComment(node);
267 try {
268 node.restore(version, true);
269 } catch (InvalidItemStateException e) {
270 node.refresh(false);
271 node.restore(version, true);
272 }
273 AlertUtil.setMessage(MessagesManager.get("versions.restore.latest.success"));
274 }
275 catch (Exception e) {
276 log.error("can't restore", e);
277 AlertUtil.setMessage(MessagesManager.get("versions.restore.exception", new String[]{e.getMessage()}));
278 }
279 return show();
280 }
281
282 public String restoreRecursive() {
283 try {
284 restoreRecursive(this.getNode(), this.getVersionLabel());
285 AlertUtil.setMessage(MessagesManager.get("versions.restore.latest.success"));
286 } catch (Exception e) {
287 log.error("can't restore", e);
288 AlertUtil.setMessage(MessagesManager.get("versions.restore.exception", new String[]{e.getMessage()}));
289 }
290 return show();
291 }
292
293 private String restoreRecursive(Content node, String version) throws UnsupportedRepositoryOperationException, RepositoryException {
294 addComment(node, version);
295 node.addVersion();
296 cleanComment(node);
297
298 try {
299 node.restore(version, true);
300 } catch (InvalidItemStateException e) {
301 node.refresh(false);
302 node.restore(version, true);
303 }
304
305
306 for (Content child : node.getChildren()) {
307
308 Collection<Version> versions = VersionUtil.getSortedNotDeletedVersions(child);
309 if (versions.size() > 0) {
310 String childVersion = versions.iterator().next().getName();
311 restoreRecursive(child, childVersion);
312 }
313 }
314 return show();
315 }
316
317
318
319
320 public String getPath() {
321 return this.path;
322 }
323
324
325
326
327 public void setPath(String path) {
328 this.path = path;
329 }
330
331
332
333
334 public String getRepository() {
335 return this.repository;
336 }
337
338
339
340
341 public void setRepository(String repository) {
342 this.repository = repository;
343 }
344
345 @Override
346 public String onRender() {
347 return FreemarkerUtil.process(VersionsList.class, this);
348 }
349
350
351
352
353 public String getVersionLabel() {
354 return this.versionLabel;
355 }
356
357
358
359
360 public void setVersionLabel(String versionLabel) {
361 this.versionLabel = versionLabel;
362 }
363
364 public String getOnDiffFunction() {
365 return "function(versionLabel){}";
366 }
367
368 public String getJsExecutedAfterSaving() {
369 return this.jsExecutedAfterSaving;
370 }
371
372 public void setJsExecutedAfterSaving(String jsExecutedAfterSaving) {
373 this.jsExecutedAfterSaving = jsExecutedAfterSaving;
374 }
375 }