]> git.argeo.org Git - lgpl/argeo-commons.git/blob - jackrabbit/JackrabbitContainer.java
Prepare next development cycle
[lgpl/argeo-commons.git] / 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
89 public void afterPropertiesSet() throws Exception {
90 // remote repository
91 if (uri != null && !uri.trim().equals("")) {
92 Map<String, String> params = new HashMap<String, String>();
93 params.put(org.apache.jackrabbit.commons.JcrUtils.REPOSITORY_URI,
94 uri);
95 repository = new Jcr2davRepositoryFactory().getRepository(params);
96 if (repository == null)
97 throw new ArgeoException("Remote Davex repository " + uri
98 + " not found");
99 log.info("Initialized Jackrabbit repository " + repository
100 + " from uri " + uri);
101 // do not perform further initialization since we assume that the
102 // remote repository has been properly configured
103 return;
104 }
105
106 // local repository
107 if (inMemory && homeDirectory.exists()) {
108 FileUtils.deleteDirectory(homeDirectory);
109 log.warn("Deleted Jackrabbit home directory " + homeDirectory);
110 }
111
112 RepositoryConfig config;
113 InputStream in = configuration.getInputStream();
114 InputStream propsIn = null;
115 try {
116 Properties vars = new Properties();
117 if (variables != null) {
118 propsIn = variables.getInputStream();
119 vars.load(propsIn);
120 }
121 // override with system properties
122 vars.putAll(System.getProperties());
123 vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE,
124 homeDirectory.getCanonicalPath());
125 config = RepositoryConfig.create(new InputSource(in), vars);
126 } catch (Exception e) {
127 throw new RuntimeException("Cannot read configuration", e);
128 } finally {
129 IOUtils.closeQuietly(in);
130 IOUtils.closeQuietly(propsIn);
131 }
132
133 if (inMemory)
134 repository = new TransientRepository(config);
135 else
136 repository = RepositoryImpl.create(config);
137
138 importNodeTypeDefinitions(repository);
139
140 log.info("Initialized Jackrabbit repository " + repository + " in "
141 + homeDirectory + " with config " + configuration);
142 }
143
144 /**
145 * Import declared node type definitions, trying to update them if they have
146 * changed. In case of failures an error will be logged but no exception
147 * will be thrown.
148 */
149 protected void importNodeTypeDefinitions(final Repository repository) {
150 if (systemExecutor == null) {
151 log.warn("No system executor found");
152 return;
153 }
154
155 systemExecutor.execute(new Runnable() {
156 public void run() {
157 Reader reader = null;
158 Session session = null;
159 try {
160 session = repository.login();
161 // Load cnds as resources
162 for (String resUrl : cndFiles) {
163 Resource res = resourceLoader.getResource(resUrl);
164 byte[] arr = IOUtils.toByteArray(res.getInputStream());
165 reader = new InputStreamReader(
166 new ByteArrayInputStream(arr));
167 CndImporter.registerNodeTypes(reader, session, true);
168 }
169 session.save();
170 } catch (Exception e) {
171 log.error(
172 "Cannot import node type definitions " + cndFiles,
173 e);
174 JcrUtils.discardQuietly(session);
175 } finally {
176 IOUtils.closeQuietly(reader);
177 JcrUtils.logoutQuietly(session);
178 }
179 }
180 });
181
182 }
183
184 public void destroy() throws Exception {
185 if (repository != null) {
186 if (repository instanceof JackrabbitRepository)
187 ((JackrabbitRepository) repository).shutdown();
188 else if (repository instanceof RepositoryImpl)
189 ((RepositoryImpl) repository).shutdown();
190 else if (repository instanceof TransientRepository)
191 ((TransientRepository) repository).shutdown();
192 }
193
194 if (inMemory)
195 if (homeDirectory.exists()) {
196 FileUtils.deleteDirectory(homeDirectory);
197 if (log.isDebugEnabled())
198 log.debug("Deleted Jackrabbit home directory "
199 + homeDirectory);
200 }
201
202 if (uri != null && !uri.trim().equals(""))
203 log.info("Destroyed Jackrabbit repository with uri " + uri);
204 else
205 log.info("Destroyed Jackrabbit repository " + repository + " in "
206 + homeDirectory + " with config " + configuration);
207 }
208
209 // JCR REPOSITORY (delegated)
210 public String getDescriptor(String key) {
211 return repository.getDescriptor(key);
212 }
213
214 public String[] getDescriptorKeys() {
215 return repository.getDescriptorKeys();
216 }
217
218 public Session login() throws LoginException, RepositoryException {
219 Session session = repository.login();
220 processNewSession(session);
221 return session;
222 }
223
224 public Session login(Credentials credentials, String workspaceName)
225 throws LoginException, NoSuchWorkspaceException,
226 RepositoryException {
227 Session session;
228 try {
229 session = repository.login(credentials, workspaceName);
230 } catch (NoSuchWorkspaceException e) {
231 if (autocreateWorkspaces)
232 session = createWorkspaceAndLogsIn(credentials, workspaceName);
233 else
234 throw e;
235 }
236 processNewSession(session);
237 return session;
238 }
239
240 public Session login(Credentials credentials) throws LoginException,
241 RepositoryException {
242 Session session = repository.login(credentials);
243 processNewSession(session);
244 return session;
245 }
246
247 public Session login(String workspaceName) throws LoginException,
248 NoSuchWorkspaceException, RepositoryException {
249 Session session;
250 try {
251 session = repository.login(workspaceName);
252 } catch (NoSuchWorkspaceException e) {
253 if (autocreateWorkspaces)
254 session = createWorkspaceAndLogsIn(null, workspaceName);
255 else
256 throw e;
257 }
258 processNewSession(session);
259 return session;
260 }
261
262 protected synchronized void processNewSession(Session session) {
263 try {
264 NamespaceHelper namespaceHelper = new NamespaceHelper(session);
265 namespaceHelper.registerNamespaces(namespaces);
266 } catch (Exception e) {
267 throw new ArgeoException("Cannot process new session", e);
268 }
269 }
270
271 /**
272 * Logs in to the default workspace, creates the required workspace, logs
273 * out, logs in to the required workspace.
274 */
275 protected Session createWorkspaceAndLogsIn(Credentials credentials,
276 String workspaceName) throws RepositoryException {
277 if (workspaceName == null)
278 throw new ArgeoException("No workspace specified.");
279 Session session = repository.login(credentials);
280 session.getWorkspace().createWorkspace(workspaceName);
281 session.logout();
282 return repository.login(credentials, workspaceName);
283 }
284
285 public void setResourceLoader(ResourceLoader resourceLoader) {
286 this.resourceLoader = resourceLoader;
287 }
288
289 public boolean isStandardDescriptor(String key) {
290 return repository.isStandardDescriptor(key);
291 }
292
293 public boolean isSingleValueDescriptor(String key) {
294 return repository.isSingleValueDescriptor(key);
295 }
296
297 public Value getDescriptorValue(String key) {
298 return repository.getDescriptorValue(key);
299 }
300
301 public Value[] getDescriptorValues(String key) {
302 return repository.getDescriptorValues(key);
303 }
304
305 // BEANS METHODS
306 public void setHomeDirectory(File homeDirectory) {
307 this.homeDirectory = homeDirectory;
308 }
309
310 public void setConfiguration(Resource configuration) {
311 this.configuration = configuration;
312 }
313
314 public void setInMemory(Boolean inMemory) {
315 this.inMemory = inMemory;
316 }
317
318 public void setNamespaces(Map<String, String> namespaces) {
319 this.namespaces = namespaces;
320 }
321
322 public void setCndFiles(List<String> cndFiles) {
323 this.cndFiles = cndFiles;
324 }
325
326 public void setVariables(Resource variables) {
327 this.variables = variables;
328 }
329
330 public void setUri(String uri) {
331 this.uri = uri;
332 }
333
334 public void setSystemExecutor(Executor systemExecutor) {
335 this.systemExecutor = systemExecutor;
336 }
337
338 }