]> git.argeo.org Git - lgpl/argeo-commons.git/blob - server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java
Introduce minimal Jackrabbit
[lgpl/argeo-commons.git] / server / runtime / org.argeo.server.jackrabbit / src / main / java / org / argeo / jackrabbit / JackrabbitContainer.java
1 /*
2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 package org.argeo.jackrabbit;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.File;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.io.Reader;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29 import java.util.concurrent.Executor;
30
31 import javax.jcr.Credentials;
32 import javax.jcr.LoginException;
33 import javax.jcr.NoSuchWorkspaceException;
34 import javax.jcr.Repository;
35 import javax.jcr.RepositoryException;
36 import javax.jcr.Session;
37 import javax.jcr.Value;
38
39 import org.apache.commons.io.FileUtils;
40 import org.apache.commons.io.IOUtils;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.apache.jackrabbit.api.JackrabbitRepository;
44 import org.apache.jackrabbit.commons.NamespaceHelper;
45 import org.apache.jackrabbit.commons.cnd.CndImporter;
46 import org.apache.jackrabbit.core.RepositoryImpl;
47 import org.apache.jackrabbit.core.TransientRepository;
48 import org.apache.jackrabbit.core.config.RepositoryConfig;
49 import org.apache.jackrabbit.core.config.RepositoryConfigurationParser;
50 import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
51 import org.argeo.ArgeoException;
52 import org.argeo.jcr.JcrUtils;
53 import org.springframework.beans.factory.DisposableBean;
54 import org.springframework.beans.factory.InitializingBean;
55 import org.springframework.context.ResourceLoaderAware;
56 import org.springframework.core.io.Resource;
57 import org.springframework.core.io.ResourceLoader;
58 import org.xml.sax.InputSource;
59
60 /**
61 * Wrapper around a Jackrabbit repository which allows to configure it in Spring
62 * and expose it as a {@link Repository}.
63 */
64 public class JackrabbitContainer implements InitializingBean, DisposableBean,
65 Repository, ResourceLoaderAware {
66 private Log log = LogFactory.getLog(JackrabbitContainer.class);
67
68 private Resource configuration;
69 private File homeDirectory;
70 private Resource variables;
71
72 private Boolean inMemory = false;
73 private String uri = null;
74
75 private Repository repository;
76
77 private ResourceLoader resourceLoader;
78
79 /** Node type definitions in CND format */
80 private List<String> cndFiles = new ArrayList<String>();
81
82 /** Namespaces to register: key is prefix, value namespace */
83 private Map<String, String> namespaces = new HashMap<String, String>();
84
85 private Boolean autocreateWorkspaces = false;
86
87 private Executor systemExecutor;
88 private Credentials adminCredentials;
89
90 public void afterPropertiesSet() throws Exception {
91 // remote repository
92 if (uri != null && !uri.trim().equals("")) {
93 Map<String, String> params = new HashMap<String, String>();
94 params.put(org.apache.jackrabbit.commons.JcrUtils.REPOSITORY_URI,
95 uri);
96 repository = new Jcr2davRepositoryFactory().getRepository(params);
97 if (repository == null)
98 throw new ArgeoException("Remote Davex repository " + uri
99 + " not found");
100 log.info("Initialized Jackrabbit repository " + repository
101 + " from URI " + uri);
102 // do not perform further initialization since we assume that the
103 // remote repository has been properly configured
104 return;
105 }
106
107 // local repository
108 if (inMemory && homeDirectory.exists()) {
109 FileUtils.deleteDirectory(homeDirectory);
110 log.warn("Deleted Jackrabbit home directory " + homeDirectory);
111 }
112
113 RepositoryConfig config;
114 InputStream in = configuration.getInputStream();
115 InputStream propsIn = null;
116 try {
117 Properties vars = new Properties();
118 if (variables != null) {
119 propsIn = variables.getInputStream();
120 vars.load(propsIn);
121 }
122 // override with system properties
123 vars.putAll(System.getProperties());
124 vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE,
125 homeDirectory.getCanonicalPath());
126 config = RepositoryConfig.create(new InputSource(in), vars);
127 } catch (Exception e) {
128 throw new RuntimeException("Cannot read configuration", e);
129 } finally {
130 IOUtils.closeQuietly(in);
131 IOUtils.closeQuietly(propsIn);
132 }
133
134 if (inMemory)
135 repository = new TransientRepository(config);
136 else
137 repository = RepositoryImpl.create(config);
138
139 if (cndFiles != null && cndFiles.size() > 0)
140 importNodeTypeDefinitions(repository);
141
142 log.info("Initialized Jackrabbit repository " + repository + " in "
143 + homeDirectory + " with config " + configuration);
144 }
145
146 /**
147 * Import declared node type definitions, trying to update them if they have
148 * changed. In case of failures an error will be logged but no exception
149 * will be thrown.
150 */
151 protected void importNodeTypeDefinitions(final Repository repository) {
152 final Credentials credentialsToUse;
153 if (systemExecutor == null) {
154 if (adminCredentials == null)
155 throw new ArgeoException(
156 "No system executor or admin credentials found");
157 credentialsToUse = adminCredentials;
158 } else {
159 credentialsToUse = null;
160 }
161
162 Runnable action = new Runnable() {
163 public void run() {
164 Reader reader = null;
165 Session session = null;
166 try {
167 session = repository.login(credentialsToUse);
168 processNewSession(session);
169 // Load cnds as resources
170 for (String resUrl : cndFiles) {
171 Resource res = resourceLoader.getResource(resUrl);
172 byte[] arr = IOUtils.toByteArray(res.getInputStream());
173 reader = new InputStreamReader(
174 new ByteArrayInputStream(arr));
175 CndImporter.registerNodeTypes(reader, session, true);
176 }
177 session.save();
178 } catch (Exception e) {
179 log.error(
180 "Cannot import node type definitions " + cndFiles,
181 e);
182 JcrUtils.discardQuietly(session);
183 } finally {
184 IOUtils.closeQuietly(reader);
185 JcrUtils.logoutQuietly(session);
186 }
187 }
188 };
189
190 if (systemExecutor != null)
191 systemExecutor.execute(action);
192 else
193 action.run();
194 }
195
196 public void destroy() throws Exception {
197 if (repository != null) {
198 if (repository instanceof JackrabbitRepository)
199 ((JackrabbitRepository) repository).shutdown();
200 else if (repository instanceof RepositoryImpl)
201 ((RepositoryImpl) repository).shutdown();
202 else if (repository instanceof TransientRepository)
203 ((TransientRepository) repository).shutdown();
204 }
205
206 if (inMemory)
207 if (homeDirectory.exists()) {
208 FileUtils.deleteDirectory(homeDirectory);
209 if (log.isDebugEnabled())
210 log.debug("Deleted Jackrabbit home directory "
211 + homeDirectory);
212 }
213
214 if (uri != null && !uri.trim().equals(""))
215 log.info("Destroyed Jackrabbit repository with uri " + uri);
216 else
217 log.info("Destroyed Jackrabbit repository " + repository + " in "
218 + homeDirectory + " with config " + configuration);
219 }
220
221 // JCR REPOSITORY (delegated)
222 public String getDescriptor(String key) {
223 return repository.getDescriptor(key);
224 }
225
226 public String[] getDescriptorKeys() {
227 return repository.getDescriptorKeys();
228 }
229
230 public Session login() throws LoginException, RepositoryException {
231 Session session = repository.login();
232 processNewSession(session);
233 return session;
234 }
235
236 public Session login(Credentials credentials, String workspaceName)
237 throws LoginException, NoSuchWorkspaceException,
238 RepositoryException {
239 Session session;
240 try {
241 session = repository.login(credentials, workspaceName);
242 } catch (NoSuchWorkspaceException e) {
243 if (autocreateWorkspaces)
244 session = createWorkspaceAndLogsIn(credentials, workspaceName);
245 else
246 throw e;
247 }
248 processNewSession(session);
249 return session;
250 }
251
252 public Session login(Credentials credentials) throws LoginException,
253 RepositoryException {
254 Session session = repository.login(credentials);
255 processNewSession(session);
256 return session;
257 }
258
259 public Session login(String workspaceName) throws LoginException,
260 NoSuchWorkspaceException, RepositoryException {
261 Session session;
262 try {
263 session = repository.login(workspaceName);
264 } catch (NoSuchWorkspaceException e) {
265 if (autocreateWorkspaces)
266 session = createWorkspaceAndLogsIn(null, workspaceName);
267 else
268 throw e;
269 }
270 processNewSession(session);
271 return session;
272 }
273
274 protected synchronized void processNewSession(Session session) {
275 try {
276 NamespaceHelper namespaceHelper = new NamespaceHelper(session);
277 namespaceHelper.registerNamespaces(namespaces);
278
279 } catch (Exception e) {
280 throw new ArgeoException("Cannot process new session", e);
281 }
282 }
283
284 /**
285 * Logs in to the default workspace, creates the required workspace, logs
286 * out, logs in to the required workspace.
287 */
288 protected Session createWorkspaceAndLogsIn(Credentials credentials,
289 String workspaceName) throws RepositoryException {
290 if (workspaceName == null)
291 throw new ArgeoException("No workspace specified.");
292 Session session = repository.login(credentials);
293 session.getWorkspace().createWorkspace(workspaceName);
294 session.logout();
295 return repository.login(credentials, workspaceName);
296 }
297
298 public void setResourceLoader(ResourceLoader resourceLoader) {
299 this.resourceLoader = resourceLoader;
300 }
301
302 public boolean isStandardDescriptor(String key) {
303 return repository.isStandardDescriptor(key);
304 }
305
306 public boolean isSingleValueDescriptor(String key) {
307 return repository.isSingleValueDescriptor(key);
308 }
309
310 public Value getDescriptorValue(String key) {
311 return repository.getDescriptorValue(key);
312 }
313
314 public Value[] getDescriptorValues(String key) {
315 return repository.getDescriptorValues(key);
316 }
317
318 // BEANS METHODS
319 public void setHomeDirectory(File homeDirectory) {
320 this.homeDirectory = homeDirectory;
321 }
322
323 public void setConfiguration(Resource configuration) {
324 this.configuration = configuration;
325 }
326
327 public void setInMemory(Boolean inMemory) {
328 this.inMemory = inMemory;
329 }
330
331 public void setNamespaces(Map<String, String> namespaces) {
332 this.namespaces = namespaces;
333 }
334
335 public void setCndFiles(List<String> cndFiles) {
336 this.cndFiles = cndFiles;
337 }
338
339 public void setVariables(Resource variables) {
340 this.variables = variables;
341 }
342
343 public void setUri(String uri) {
344 this.uri = uri;
345 }
346
347 public void setSystemExecutor(Executor systemExecutor) {
348 this.systemExecutor = systemExecutor;
349 }
350
351 public void setAdminCredentials(Credentials adminCredentials) {
352 this.adminCredentials = adminCredentials;
353 }
354
355 }