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