1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.exoplatform.services.cms.documents;
20
21 import org.exoplatform.services.log.ExoLogger;
22 import org.exoplatform.services.log.Log;
23
24 import javax.jcr.Node;
25 import javax.jcr.RepositoryException;
26 import javax.jcr.Value;
27 import javax.jcr.version.Version;
28 import javax.jcr.version.VersionHistory;
29 import javax.jcr.version.VersionIterator;
30 import java.util.*;
31
32 public class VersionHistoryUtils {
33
34 protected static final Log log = ExoLogger.getLogger(VersionHistoryUtils.class);
35
36 private static final int DOCUMENT_AUTO_DEFAULT_VERSION_MAX = 0;
37 private static final int DOCUMENT_AUTO_DEFAULT_VERSION_EXPIRED = 0;
38
39 public static final String NT_FILE = "nt:file";
40 public static final String MIX_VERSIONABLE = "mix:versionable";
41
42
43 public static final String MIX_DISPLAY_VERSION_NAME = "mix:versionDisplayName";
44
45 public static final String MAX_VERSION_PROPERTY = "exo:maxVersion";
46
47 public static final String LIST_VERSION_PROPERTY = "exo:versionList";
48 public static final String VERSION_SEPARATOR = ":";
49
50 private static String maxAllowVersionProp = "jcr.documents.versions.max";
51 private static String expirationTimeProp = "jcr.documents.versions.expiration";
52
53 private static int maxAllowVersion;
54 private static long maxLiveTime;
55
56 static {
57 try {
58 maxAllowVersion = Integer.parseInt(System.getProperty(maxAllowVersionProp));
59 maxLiveTime = Integer.parseInt(System.getProperty(expirationTimeProp));
60
61 if(maxAllowVersion < 0) maxAllowVersion = DOCUMENT_AUTO_DEFAULT_VERSION_MAX;
62 if(maxLiveTime < 0) maxLiveTime = DOCUMENT_AUTO_DEFAULT_VERSION_EXPIRED;
63 }catch(NumberFormatException nex){
64 maxAllowVersion = DOCUMENT_AUTO_DEFAULT_VERSION_MAX;
65 maxLiveTime = DOCUMENT_AUTO_DEFAULT_VERSION_EXPIRED;
66 }
67 maxLiveTime = maxLiveTime * 24 * 60 * 60 * 1000;
68 }
69
70
71
72
73
74
75 public static Version createVersion(Node nodeVersioning) throws Exception {
76 if(!nodeVersioning.isNodeType(NT_FILE)) {
77 if(log.isDebugEnabled()){
78 log.debug("Version history is not impact with non-nt:file documents, there'is not any version created.");
79 }
80 return null;
81 }
82
83 if(!nodeVersioning.isNodeType(MIX_VERSIONABLE)){
84 if(nodeVersioning.canAddMixin(MIX_VERSIONABLE)) {
85 nodeVersioning.addMixin(MIX_VERSIONABLE);
86 nodeVersioning.save();
87 }
88 return null;
89 }
90 Version version = null;
91 if (!nodeVersioning.isCheckedOut()) {
92 nodeVersioning.checkout();
93 version = nodeVersioning.getBaseVersion();
94 } else {
95 version = nodeVersioning.checkin();
96 nodeVersioning.checkout();
97 }
98
99
100
101 if (version != null && nodeVersioning.isNodeType(VersionHistoryUtils.MIX_DISPLAY_VERSION_NAME)) {
102 int maxVersion = 0;
103 if(nodeVersioning.hasProperty(MAX_VERSION_PROPERTY)){
104
105 maxVersion = (int) nodeVersioning.getProperty(VersionHistoryUtils.MAX_VERSION_PROPERTY).getLong();
106
107 nodeVersioning.setProperty(MAX_VERSION_PROPERTY, maxVersion +1);
108 }
109
110 String newRef = version.getName() + VERSION_SEPARATOR + maxVersion;
111 List<Value> newValues = new ArrayList<Value>();
112 Value[] values;
113 if(nodeVersioning.hasProperty(LIST_VERSION_PROPERTY)){
114 values = nodeVersioning.getProperty(LIST_VERSION_PROPERTY).getValues();
115 newValues.addAll(Arrays.<Value>asList(values));
116 }
117 Value value2add = nodeVersioning.getSession().getValueFactory().createValue(newRef);
118 newValues.add(value2add);
119
120 nodeVersioning.setProperty(VersionHistoryUtils.LIST_VERSION_PROPERTY, newValues.toArray(new Value[newValues.size()]));
121 nodeVersioning.save();
122 }
123
124 if(maxAllowVersion!= DOCUMENT_AUTO_DEFAULT_VERSION_MAX || maxLiveTime != DOCUMENT_AUTO_DEFAULT_VERSION_EXPIRED) {
125 removeRedundant(nodeVersioning);
126 }
127 nodeVersioning.save();
128 return version;
129 }
130
131
132
133
134
135
136
137 public static void removeVersion(Node node, String versionName) throws RepositoryException {
138 VersionHistory versionHistory = node.getVersionHistory();
139
140
141 if (node.getBaseVersion().getName().equals(versionName)) {
142 if (node.canAddMixin(MIX_DISPLAY_VERSION_NAME)) {
143
144 int maxVersion = Integer.parseInt(versionName) + 1;
145 node.addMixin(MIX_DISPLAY_VERSION_NAME);
146 node.setProperty(MAX_VERSION_PROPERTY, maxVersion);
147 } else {
148
149 removeRefVersionName(node, versionName);
150 }
151 node.save();
152 } else if (node.isNodeType(MIX_DISPLAY_VERSION_NAME)) {
153
154 removeRefVersionName(node, versionName);
155 node.save();
156 }
157 versionHistory.removeVersion(versionName);
158 }
159
160
161
162
163
164
165
166
167 private static void removeRedundant(Node nodeVersioning) throws Exception{
168 VersionHistory versionHistory = nodeVersioning.getVersionHistory();
169 String baseVersion = nodeVersioning.getBaseVersion().getName();
170 String rootVersion = nodeVersioning.getVersionHistory().getRootVersion().getName();
171 VersionIterator versions = versionHistory.getAllVersions();
172 Date currentDate = new Date();
173 Map<String, String> lstVersions = new HashMap<String, String>();
174 List<String> lstVersionTime = new ArrayList<String>();
175 while (versions.hasNext()) {
176 Version version = versions.nextVersion();
177 if(rootVersion.equals(version.getName()) || baseVersion.equals(version.getName())) continue;
178
179 if (maxLiveTime!= DOCUMENT_AUTO_DEFAULT_VERSION_EXPIRED &&
180 currentDate.getTime() - version.getCreated().getTime().getTime() > maxLiveTime) {
181 versionHistory.removeVersion(version.getName());
182 } else {
183 lstVersions.put(String.valueOf(version.getCreated().getTimeInMillis()), version.getName());
184 lstVersionTime.add(String.valueOf(version.getCreated().getTimeInMillis()));
185 }
186 }
187 if (maxAllowVersion <= lstVersionTime.size() && maxAllowVersion!= DOCUMENT_AUTO_DEFAULT_VERSION_MAX) {
188 Collections.sort(lstVersionTime);
189 String[] lsts = lstVersionTime.toArray(new String[lstVersionTime.size()]);
190 for (int j = 0; j <= lsts.length - maxAllowVersion; j++) {
191 versionHistory.removeVersion(lstVersions.get(lsts[j]));
192 }
193 }
194 }
195
196
197
198
199
200
201
202 private static void removeRefVersionName(Node node, String versionName) throws RepositoryException {
203 if(node.hasProperty(LIST_VERSION_PROPERTY)){
204 if(node.hasProperty(VersionHistoryUtils.LIST_VERSION_PROPERTY)){
205 Value[] values = node.getProperty(VersionHistoryUtils.LIST_VERSION_PROPERTY).getValues();
206 List<Value> newValues = new ArrayList<Value>();
207 for (Value value : values){
208 if (!value.getString().split(VERSION_SEPARATOR)[0].equals(versionName))
209 newValues.add(value);
210 }
211 node.setProperty(VersionHistoryUtils.LIST_VERSION_PROPERTY, newValues.toArray(new Value[newValues.size()]));
212 }
213 }
214 }
215 }