1 package org
.argeo
.cms
.internal
.jcr
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
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
;
15 import javax
.jcr
.RepositoryException
;
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
.internal
.kernel
.CmsPaths
;
26 import org
.xml
.sax
.InputSource
;
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);
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();
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);
47 return repositoryContext
;
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")) {
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,
62 // custom configuration parser
63 CustomRepositoryConfigurationParser parser
= new CustomRepositoryConfigurationParser(jackrabbitVars
);
64 parser
.setAccessControlProviderClassLoader(cl
);
65 RepositoryConfig repositoryConfig
= parser
.parseRepositoryConfig(config
);
66 repositoryConfig
.init();
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);
74 return repositoryConfig
;
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
));
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
);
95 clusterId
= clusterIdProp
;
99 String homeUri
= props
.getProperty(RepoConf
.labeledUri
.name());
101 if (homeUri
== null) {
102 String cn
= props
.getProperty(NodeConstants
.CN
);
104 if (clusterId
!= null) {
105 homePath
= CmsPaths
.getRepoDirPath(cn
+ '/' + clusterId
);
107 homePath
= CmsPaths
.getRepoDirPath(cn
);
111 URI uri
= new URI(homeUri
);
112 String host
= uri
.getHost();
113 if (host
== null || host
.trim().equals("")) {
114 homePath
= Paths
.get(uri
).toAbsolutePath();
116 // TODO remote at this stage?
117 throw new IllegalArgumentException("Cannot manage repository path for host " + host
);
119 } catch (URISyntaxException e
) {
120 throw new IllegalArgumentException("Invalid repository home URI", e
);
123 // TODO use Jackrabbit API (?)
124 Path rootUuidPath
= homePath
.resolve("repository/meta/rootUUID");
126 if (!Files
.exists(rootUuidPath
)) {
127 Files
.createDirectories(rootUuidPath
.getParent());
128 Files
.write(rootUuidPath
, UUID
.randomUUID().toString().getBytes());
130 // File homeDir = homePath.toFile();
132 } catch (IOException e
) {
133 throw new RuntimeException("Cannot set up repository home " + homePath
, e
);
135 // home cannot be overridden
136 props
.put(RepositoryConfigurationParser
.REPOSITORY_HOME_VARIABLE
, homePath
.toString());
138 setProp(props
, RepoConf
.indexesBase
, CmsPaths
.getRepoIndexesBase().toString());
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
);
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
, "");
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
, "");
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");
178 throw new IllegalArgumentException("Unsupported node type " + type
);
183 private void setProp(Properties props
, RepoConf key
, String def
) {
184 Object value
= props
.get(key
.name());
188 value
= key
.getDefault();
190 props
.put(key
.name(), value
.toString());
193 private void setProp(Properties props
, RepoConf key
) {
194 setProp(props
, key
, null);
197 private String
prop(Dictionary
<String
, ?
> properties
, RepoConf key
) {
198 Object value
= properties
.get(key
.name());
200 return key
.getDefault() != null ? key
.getDefault().toString() : null;
202 return value
.toString();
205 private RepositoryContext
createJackrabbitRepository(RepositoryConfig repositoryConfig
) throws RepositoryException
{
206 ClassLoader currentContextCl
= Thread
.currentThread().getContextClassLoader();
207 Thread
.currentThread().setContextClassLoader(RepositoryBuilder
.class.getClassLoader());
209 long begin
= System
.currentTimeMillis();
211 // Actual repository creation
213 RepositoryContext repositoryContext
= RepositoryContext
.create(repositoryConfig
);
215 double duration
= ((double) (System
.currentTimeMillis() - begin
)) / 1000;
216 if (log
.isDebugEnabled())
218 "Created Jackrabbit repository in " + duration
+ " s, home: " + repositoryConfig
.getHomeDir());
220 return repositoryContext
;
222 Thread
.currentThread().setContextClassLoader(currentContextCl
);