]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.jcr/src/org/argeo/cms/internal/jcr/RepositoryBuilder.java
Simplify Argeo Commons project structure
[lgpl/argeo-commons.git] / org.argeo.cms.jcr / src / org / argeo / cms / internal / jcr / RepositoryBuilder.java
1 package org.argeo.cms.internal.jcr;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URI;
6 import java.net.URISyntaxException;
7 import java.nio.file.Files;
8 import java.nio.file.Path;
9 import java.nio.file.Paths;
10 import java.util.Dictionary;
11 import java.util.Enumeration;
12 import java.util.Properties;
13 import java.util.UUID;
14
15 import javax.jcr.RepositoryException;
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.apache.jackrabbit.core.RepositoryContext;
20 import org.apache.jackrabbit.core.RepositoryImpl;
21 import org.apache.jackrabbit.core.cache.CacheManager;
22 import org.apache.jackrabbit.core.config.RepositoryConfig;
23 import org.apache.jackrabbit.core.config.RepositoryConfigurationParser;
24 import org.argeo.api.NodeConstants;
25 import org.argeo.cms.jcr.internal.CmsPaths;
26 import org.xml.sax.InputSource;
27
28 /** Can interpret properties in order to create an actual JCR repository. */
29 public class RepositoryBuilder {
30 private final static Log log = LogFactory.getLog(RepositoryBuilder.class);
31
32 public RepositoryContext createRepositoryContext(Dictionary<String, ?> properties)
33 throws RepositoryException, IOException {
34 RepositoryConfig repositoryConfig = createRepositoryConfig(properties);
35 RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig);
36 RepositoryImpl repository = repositoryContext.getRepository();
37
38 // cache
39 Object maxCacheMbStr = prop(properties, RepoConf.maxCacheMB);
40 if (maxCacheMbStr != null) {
41 Integer maxCacheMB = Integer.parseInt(maxCacheMbStr.toString());
42 CacheManager cacheManager = repository.getCacheManager();
43 cacheManager.setMaxMemory(maxCacheMB * 1024l * 1024l);
44 cacheManager.setMaxMemoryPerCache((maxCacheMB / 4) * 1024l * 1024l);
45 }
46
47 return repositoryContext;
48 }
49
50 RepositoryConfig createRepositoryConfig(Dictionary<String, ?> properties) throws RepositoryException, IOException {
51 JackrabbitType type = JackrabbitType.valueOf(prop(properties, RepoConf.type).toString());
52 ClassLoader cl = getClass().getClassLoader();
53 final String base = "/org/argeo/cms/internal/jcr";
54 try (InputStream in = cl.getResourceAsStream(base + "/repository-" + type.name() + ".xml")) {
55 if (in == null)
56 throw new IllegalArgumentException("Repository configuration not found");
57 InputSource config = new InputSource(in);
58 Properties jackrabbitVars = getConfigurationProperties(type, properties);
59 // RepositoryConfig repositoryConfig = RepositoryConfig.create(config,
60 // jackrabbitVars);
61
62 // custom configuration parser
63 CustomRepositoryConfigurationParser parser = new CustomRepositoryConfigurationParser(jackrabbitVars);
64 parser.setClassLoader(cl);
65 RepositoryConfig repositoryConfig = parser.parseRepositoryConfig(config);
66 repositoryConfig.init();
67
68 // set the proper classloaders
69 repositoryConfig.getSecurityConfig().getSecurityManagerConfig().setClassLoader(cl);
70 repositoryConfig.getSecurityConfig().getAccessManagerConfig().setClassLoader(cl);
71 // for (WorkspaceConfig workspaceConfig : repositoryConfig.getWorkspaceConfigs()) {
72 // workspaceConfig.getSecurityConfig().getAccessControlProviderConfig().setClassLoader(cl);
73 // }
74 return repositoryConfig;
75 }
76 }
77
78 private Properties getConfigurationProperties(JackrabbitType type, Dictionary<String, ?> properties) {
79 Properties props = new Properties();
80 for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
81 String key = keys.nextElement();
82 props.put(key, properties.get(key));
83 }
84
85 // cluster id
86 // cf. https://wiki.apache.org/jackrabbit/Clustering
87 // TODO deal with multiple repos
88 String clusterId = System.getProperty("org.apache.jackrabbit.core.cluster.node_id");
89 String clusterIdProp = props.getProperty(RepoConf.clusterId.name());
90 if (clusterId != null) {
91 if (clusterIdProp != null)
92 throw new IllegalArgumentException("Cluster id defined as System properties and in deploy config");
93 props.put(RepoConf.clusterId.name(), clusterId);
94 } else {
95 clusterId = clusterIdProp;
96 }
97
98 // home
99 String homeUri = props.getProperty(RepoConf.labeledUri.name());
100 Path homePath;
101 if (homeUri == null) {
102 String cn = props.getProperty(NodeConstants.CN);
103 assert cn != null;
104 if (clusterId != null) {
105 homePath = CmsPaths.getRepoDirPath(cn + '/' + clusterId);
106 } else {
107 homePath = CmsPaths.getRepoDirPath(cn);
108 }
109 } else {
110 try {
111 URI uri = new URI(homeUri);
112 String host = uri.getHost();
113 if (host == null || host.trim().equals("")) {
114 homePath = Paths.get(uri).toAbsolutePath();
115 } else {
116 // TODO remote at this stage?
117 throw new IllegalArgumentException("Cannot manage repository path for host " + host);
118 }
119 } catch (URISyntaxException e) {
120 throw new IllegalArgumentException("Invalid repository home URI", e);
121 }
122 }
123 // TODO use Jackrabbit API (?)
124 Path rootUuidPath = homePath.resolve("repository/meta/rootUUID");
125 try {
126 if (!Files.exists(rootUuidPath)) {
127 Files.createDirectories(rootUuidPath.getParent());
128 Files.write(rootUuidPath, UUID.randomUUID().toString().getBytes());
129 }
130 // File homeDir = homePath.toFile();
131 // homeDir.mkdirs();
132 } catch (IOException e) {
133 throw new RuntimeException("Cannot set up repository home " + homePath, e);
134 }
135 // home cannot be overridden
136 props.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, homePath.toString());
137
138 setProp(props, RepoConf.indexesBase, CmsPaths.getRepoIndexesBase().toString());
139 // common
140 setProp(props, RepoConf.defaultWorkspace);
141 setProp(props, RepoConf.maxPoolSize);
142 // Jackrabbit defaults
143 setProp(props, RepoConf.bundleCacheMB);
144 // See http://wiki.apache.org/jackrabbit/Search
145 setProp(props, RepoConf.extractorPoolSize);
146 setProp(props, RepoConf.searchCacheSize);
147 setProp(props, RepoConf.maxVolatileIndexSize);
148
149 // specific
150 String dburl;
151 switch (type) {
152 case h2:
153 dburl = "jdbc:h2:" + homePath.toAbsolutePath() + "/h2/repository";
154 setProp(props, RepoConf.dburl, dburl);
155 setProp(props, RepoConf.dbuser, "sa");
156 setProp(props, RepoConf.dbpassword, "");
157 break;
158 case h2_postgresql:
159 dburl = "jdbc:h2:" + homePath.toAbsolutePath() + "/h2/repository;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE";
160 setProp(props, RepoConf.dburl, dburl);
161 setProp(props, RepoConf.dbuser, "sa");
162 setProp(props, RepoConf.dbpassword, "");
163 break;
164 case postgresql:
165 case postgresql_ds:
166 case postgresql_cluster:
167 case postgresql_cluster_ds:
168 dburl = "jdbc:postgresql://localhost/demo";
169 setProp(props, RepoConf.dburl, dburl);
170 setProp(props, RepoConf.dbuser, "argeo");
171 setProp(props, RepoConf.dbpassword, "argeo");
172 break;
173 case memory:
174 break;
175 case localfs:
176 break;
177 default:
178 throw new IllegalArgumentException("Unsupported node type " + type);
179 }
180 return props;
181 }
182
183 private void setProp(Properties props, RepoConf key, String def) {
184 Object value = props.get(key.name());
185 if (value == null)
186 value = def;
187 if (value == null)
188 value = key.getDefault();
189 if (value != null)
190 props.put(key.name(), value.toString());
191 }
192
193 private void setProp(Properties props, RepoConf key) {
194 setProp(props, key, null);
195 }
196
197 private String prop(Dictionary<String, ?> properties, RepoConf key) {
198 Object value = properties.get(key.name());
199 if (value == null)
200 return key.getDefault() != null ? key.getDefault().toString() : null;
201 else
202 return value.toString();
203 }
204
205 private RepositoryContext createJackrabbitRepository(RepositoryConfig repositoryConfig) throws RepositoryException {
206 ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
207 Thread.currentThread().setContextClassLoader(RepositoryBuilder.class.getClassLoader());
208 try {
209 long begin = System.currentTimeMillis();
210 //
211 // Actual repository creation
212 //
213 RepositoryContext repositoryContext = RepositoryContext.create(repositoryConfig);
214
215 double duration = ((double) (System.currentTimeMillis() - begin)) / 1000;
216 if (log.isDebugEnabled())
217 log.debug(
218 "Created Jackrabbit repository in " + duration + " s, home: " + repositoryConfig.getHomeDir());
219
220 return repositoryContext;
221 } finally {
222 Thread.currentThread().setContextClassLoader(currentContextCl);
223 }
224 }
225
226 }