2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.jackrabbit
;
18 import java
.io
.InputStreamReader
;
19 import java
.io
.Reader
;
21 import javax
.jcr
.Node
;
22 import javax
.jcr
.Session
;
24 import org
.apache
.commons
.io
.IOUtils
;
25 import org
.apache
.commons
.logging
.Log
;
26 import org
.apache
.commons
.logging
.LogFactory
;
27 import org
.apache
.jackrabbit
.commons
.cnd
.CndImporter
;
28 import org
.apache
.jackrabbit
.core
.config
.RepositoryConfig
;
29 import org
.argeo
.ArgeoException
;
30 import org
.argeo
.jcr
.ArgeoNames
;
31 import org
.argeo
.jcr
.JcrCallback
;
32 import org
.argeo
.jcr
.JcrUtils
;
33 import org
.springframework
.core
.io
.Resource
;
35 /** Migrate the data in a Jackrabbit repository. */
36 public class JackrabbitDataModelMigration
implements
37 Comparable
<JackrabbitDataModelMigration
> {
38 private final static Log log
= LogFactory
39 .getLog(JackrabbitDataModelMigration
.class);
41 private String dataModelNodePath
;
42 private String targetVersion
;
43 private Resource migrationCnd
;
44 private JcrCallback dataModification
;
47 * Expects an already started repository with the old data model to migrate.
48 * Expects to be run with admin rights (Repository.login() will be used).
50 * @return true if a migration was performed and the repository needs to be
51 * restarted and its caches cleared.
53 public Boolean
migrate(Session session
) {
54 long begin
= System
.currentTimeMillis();
57 // check if already migrated
58 if (!session
.itemExists(dataModelNodePath
)) {
59 log
.warn("Node " + dataModelNodePath
60 + " does not exist: nothing to migrate.");
63 Node dataModelNode
= session
.getNode(dataModelNodePath
);
64 if (dataModelNode
.hasProperty(ArgeoNames
.ARGEO_DATA_MODEL_VERSION
)) {
65 String currentVersion
= dataModelNode
.getProperty(
66 ArgeoNames
.ARGEO_DATA_MODEL_VERSION
).getString();
67 if (compareVersions(currentVersion
, targetVersion
) >= 0) {
68 log
.info("Data model at version " + currentVersion
69 + ", no need to migrate.");
74 // apply transitional CND
75 if (migrationCnd
!= null) {
76 reader
= new InputStreamReader(migrationCnd
.getInputStream());
77 CndImporter
.registerNodeTypes(reader
, session
, true);
79 log
.info("Registered migration node types from " + migrationCnd
);
83 dataModification
.execute(session
);
88 long duration
= System
.currentTimeMillis() - begin
;
89 log
.info("Migration of data model " + dataModelNodePath
+ " to "
90 + targetVersion
+ " performed in " + duration
+ "ms");
92 } catch (Exception e
) {
93 JcrUtils
.discardQuietly(session
);
94 throw new ArgeoException("Migration of data model "
95 + dataModelNodePath
+ " to " + targetVersion
+ " failed.",
98 JcrUtils
.logoutQuietly(session
);
99 IOUtils
.closeQuietly(reader
);
103 protected static int compareVersions(String version1
, String version2
) {
104 // TODO do a proper version analysis and comparison
105 return version1
.compareTo(version2
);
108 /** To be called on a stopped repository. */
109 public static void clearRepositoryCaches(RepositoryConfig repositoryConfig
) {
111 String customeNodeTypesPath
= "/nodetypes/custom_nodetypes.xml";
112 // FIXME causes weird error in Eclipse
113 //repositoryConfig.getFileSystem().deleteFile(customeNodeTypesPath);
114 if (log
.isDebugEnabled())
115 log
.debug("Cleared " + customeNodeTypesPath
);
116 } catch (Exception e
) {
117 throw new ArgeoException("Cannot clear caches", e
);
120 // File customNodeTypes = new File(home.getPath()
121 // + "/repository/nodetypes/custom_nodetypes.xml");
122 // if (customNodeTypes.exists()) {
123 // customNodeTypes.delete();
124 // if (log.isDebugEnabled())
125 // log.debug("Cleared " + customNodeTypes);
127 // log.warn("File " + customNodeTypes + " not found.");
132 * FOR USE IN (SORTED) SETS
135 public int compareTo(JackrabbitDataModelMigration dataModelMigration
) {
136 // TODO make ordering smarter
137 if (dataModelNodePath
.equals(dataModelMigration
.dataModelNodePath
))
138 return compareVersions(targetVersion
,
139 dataModelMigration
.targetVersion
);
141 return dataModelNodePath
142 .compareTo(dataModelMigration
.dataModelNodePath
);
146 public boolean equals(Object obj
) {
147 if (!(obj
instanceof JackrabbitDataModelMigration
))
149 JackrabbitDataModelMigration dataModelMigration
= (JackrabbitDataModelMigration
) obj
;
150 return dataModelNodePath
.equals(dataModelMigration
.dataModelNodePath
)
151 && targetVersion
.equals(dataModelMigration
.targetVersion
);
155 public int hashCode() {
156 return targetVersion
.hashCode();
159 public void setDataModelNodePath(String dataModelNodePath
) {
160 this.dataModelNodePath
= dataModelNodePath
;
163 public void setTargetVersion(String targetVersion
) {
164 this.targetVersion
= targetVersion
;
167 public void setMigrationCnd(Resource migrationCnd
) {
168 this.migrationCnd
= migrationCnd
;
171 public void setDataModification(JcrCallback dataModification
) {
172 this.dataModification
= dataModification
;
175 public String
getDataModelNodePath() {
176 return dataModelNodePath
;
179 public String
getTargetVersion() {
180 return targetVersion
;