001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.repository.commonimpl;
017:
018: import org.outerj.daisy.repository.*;
019: import org.outerj.daisy.repository.spi.ExtensionProvider;
020: import org.outerj.daisy.repository.acl.AclResultInfo;
021: import org.outerj.daisy.repository.acl.AclPermission;
022: import org.outerj.daisy.repository.query.QueryManager;
023: import org.outerj.daisy.repository.commonimpl.schema.CommonRepositorySchema;
024: import org.outerj.daisy.repository.commonimpl.schema.SchemaStrategy;
025: import org.outerj.daisy.repository.commonimpl.user.CommonUserManager;
026: import org.outerj.daisy.repository.commonimpl.user.UserManagementStrategy;
027: import org.outerj.daisy.repository.commonimpl.user.UserCache;
028: import org.outerj.daisy.repository.commonimpl.acl.CommonAccessManager;
029: import org.outerj.daisy.repository.commonimpl.acl.AclStrategy;
030: import org.outerj.daisy.repository.commonimpl.comment.CommonCommentManager;
031: import org.outerj.daisy.repository.commonimpl.comment.CommentStrategy;
032: import org.outerj.daisy.repository.commonimpl.variant.CommonVariantManager;
033: import org.outerj.daisy.repository.commonimpl.variant.VariantStrategy;
034: import org.outerj.daisy.repository.commonimpl.variant.VariantCache;
035: import org.outerj.daisy.repository.commonimpl.namespace.CommonNamespaceManager;
036: import org.outerj.daisy.repository.commonimpl.namespace.NamespaceCache;
037: import org.outerj.daisy.util.Constants;
038:
039: import java.util.List;
040: import java.util.ArrayList;
041: import java.util.Map;
042: import java.util.regex.Matcher;
043: import java.io.InputStream;
044:
045: public abstract class CommonRepository {
046: protected RepositoryStrategy repositoryStrategy;
047: protected DocumentStrategy documentStrategy;
048: private CommonCollectionManager collectionManager;
049: private List<RepositoryListener> listeners = new ArrayList<RepositoryListener>();
050:
051: private CommonRepositorySchema repositorySchema;
052: private CommonAccessManager commonAccessManager;
053: private CommonUserManager userManager;
054: private CommonCommentManager commentManager;
055: private CommonVariantManager variantManager;
056: private CommonNamespaceManager namespaceManager;
057: private Map<String, ExtensionProvider> extensions;
058:
059: public CommonRepository(RepositoryStrategy repositoryStrategy,
060: DocumentStrategy documentStrategy,
061: SchemaStrategy schemaStrategy, AclStrategy aclStrategy,
062: UserManagementStrategy userManagementStrategy,
063: VariantStrategy variantStrategy,
064: CollectionStrategy collectionStrategy,
065: CommentStrategy commentStrategy,
066: Map<String, ExtensionProvider> extensions,
067: AuthenticatedUser cacheUser) {
068: this .repositoryStrategy = repositoryStrategy;
069: this .documentStrategy = documentStrategy;
070: this .repositorySchema = new CommonRepositorySchema(
071: schemaStrategy, this , cacheUser);
072:
073: CollectionCache collectionCache = new CollectionCache(
074: collectionStrategy, cacheUser);
075: addListener(collectionCache);
076: this .collectionManager = new CommonCollectionManager(
077: collectionStrategy, collectionCache);
078:
079: UserCache userCache = new UserCache(userManagementStrategy,
080: cacheUser);
081: addListener(userCache);
082: this .userManager = new CommonUserManager(
083: userManagementStrategy, userCache);
084:
085: VariantCache variantCache = new VariantCache(variantStrategy,
086: cacheUser);
087: addListener(variantCache);
088: this .variantManager = new CommonVariantManager(variantStrategy,
089: variantCache);
090:
091: this .commonAccessManager = new CommonAccessManager(aclStrategy);
092: this .commentManager = new CommonCommentManager(commentStrategy);
093:
094: NamespaceCache namespaceCache = new NamespaceCache(
095: repositoryStrategy, cacheUser);
096: addListener(namespaceCache);
097: this .namespaceManager = new CommonNamespaceManager(
098: namespaceCache, repositoryStrategy);
099:
100: this .extensions = extensions;
101: }
102:
103: public CommonRepositorySchema getRepositorySchema() {
104: return repositorySchema;
105: }
106:
107: public CommonAccessManager getAccessManager() {
108: return commonAccessManager;
109: }
110:
111: public abstract QueryManager getQueryManager(AuthenticatedUser user);
112:
113: public CommonCommentManager getCommentManager() {
114: return commentManager;
115: }
116:
117: public CommonVariantManager getVariantManager() {
118: return variantManager;
119: }
120:
121: public DocumentImpl createDocument(String name,
122: long documentTypeId, long branchId, long languageId,
123: AuthenticatedUser user) {
124: try {
125: // check that the documenttype exists
126: repositorySchema.getDocumentTypeById(documentTypeId, false,
127: user);
128: // check the branch exists
129: variantManager.getBranch(branchId, false, user);
130: // check the language exists
131: variantManager.getLanguage(languageId, false, user);
132: } catch (RepositoryException e) {
133: throw new RuntimeException(e);
134: }
135: DocumentImpl newDocument = new DocumentImpl(documentStrategy,
136: this , user, documentTypeId, branchId, languageId);
137: newDocument.setName(name);
138: return newDocument;
139: }
140:
141: public DocumentImpl createDocument(String name,
142: String documentTypeName, String branchName,
143: String languageName, AuthenticatedUser user) {
144: long documentTypeId;
145: long branchId;
146: long languageId;
147: try {
148: documentTypeId = repositorySchema.getDocumentTypeByName(
149: documentTypeName, false, user).getId();
150: branchId = variantManager.getBranchByName(branchName,
151: false, user).getId();
152: languageId = variantManager.getLanguageByName(languageName,
153: false, user).getId();
154: } catch (RepositoryException e) {
155: throw new RuntimeException(e);
156: }
157: DocumentImpl newDocument = new DocumentImpl(documentStrategy,
158: this , user, documentTypeId, branchId, languageId);
159: newDocument.setName(name);
160: return newDocument;
161: }
162:
163: public Document createVariant(DocId docId, long startBranchId,
164: long startLanguageId, long startVersionId,
165: long newBranchId, long newLanguageId, boolean copyContent,
166: AuthenticatedUser user) throws RepositoryException {
167: AvailableVariant[] availableVariants = getAvailableVariants(
168: docId, user).getArray();
169: for (AvailableVariant availableVariant : availableVariants) {
170: if (availableVariant.getBranchId() == newBranchId
171: && availableVariant.getLanguageId() == newLanguageId)
172: throw new RepositoryException("Document "
173: + docId.toString()
174: + " already has the variant branch ID "
175: + newBranchId + ", language ID "
176: + newLanguageId);
177: }
178:
179: // test that the branch and languages exist
180: variantManager.getBranch(newBranchId, false, user);
181: variantManager.getLanguage(newLanguageId, false, user);
182:
183: // check that the user has write access to the start variant (otherwise everyone would be able
184: // to add new variants to whatever document, since they can modify the variant data to match the ACL rules)
185: AclResultInfo aclResultInfo = getAccessManager()
186: .getAclInfoOnLive(user, user.getId(),
187: user.getActiveRoleIds(), docId, startBranchId,
188: startLanguageId);
189: if (!aclResultInfo.isAllowed(AclPermission.READ)) {
190: throw new AccessException(
191: "A new variant can only be added if you have write access to the start variant.");
192: }
193:
194: if (copyContent) {
195: Document document = documentStrategy.createVariant(docId,
196: startBranchId, startLanguageId, startVersionId,
197: newBranchId, newLanguageId, user);
198: return document;
199: } else {
200: Document document = getDocument(docId, startBranchId,
201: startLanguageId, false, user);
202: DocumentImpl newDocument = new DocumentImpl(
203: documentStrategy, this , user, document
204: .getDocumentTypeId(), newBranchId,
205: newLanguageId);
206: newDocument.getIntimateAccess(documentStrategy).load(docId,
207: document.getLastModified(),
208: document.getLastModifier(), document.getCreated(),
209: document.getOwner(), document.isPrivate(),
210: document.getUpdateCount(),
211: document.getReferenceLanguageId());
212: newDocument.setName(document.getName());
213: DocumentVariantImpl.IntimateAccess variantInt = newDocument
214: .getIntimateAccess(documentStrategy).getVariant()
215: .getIntimateAccess(documentStrategy);
216: variantInt.setStartFrom(startBranchId, startLanguageId);
217: return newDocument;
218: }
219: }
220:
221: public Document createVariant(DocId docId, String startBranchName,
222: String startLanguageName, long startVersionId,
223: String newBranchName, String newLanguageName,
224: boolean copyContent, AuthenticatedUser user)
225: throws RepositoryException {
226: long startBranchId = variantManager.getBranchByName(
227: startBranchName, false, user).getId();
228: long startLanguageId = variantManager.getLanguageByName(
229: startLanguageName, false, user).getId();
230: long newBranchId = variantManager.getBranchByName(
231: newBranchName, false, user).getId();
232: long newLanguageId = variantManager.getLanguageByName(
233: newLanguageName, false, user).getId();
234: return createVariant(docId, startBranchId, startLanguageId,
235: startVersionId, newBranchId, newLanguageId,
236: copyContent, user);
237: }
238:
239: public Document getDocument(String documentId, long branchId,
240: long languageId, boolean updateable, AuthenticatedUser user)
241: throws RepositoryException {
242: DocId docId = DocId.parseDocIdThrowNotFound(documentId, this );
243: return getDocument(docId, branchId, languageId, updateable,
244: user);
245: }
246:
247: /**
248: * Note: it is important that all actual document retrievals go through this method, as this method
249: * is overrided in the local implementation to get objects from the cache.
250: */
251: public Document getDocument(DocId docId, long branchId,
252: long languageId, boolean updateable, AuthenticatedUser user)
253: throws RepositoryException {
254: if (updateable)
255: return documentStrategy.load(docId, branchId, languageId,
256: user);
257: else {
258: Document document = documentStrategy.load(docId, branchId,
259: languageId, user);
260: DocumentImpl documentImpl = ((DocumentWrapper) document)
261: .getWrappedDocument(documentStrategy);
262: documentImpl.makeReadOnly();
263: return document;
264: }
265: }
266:
267: public Document getDocument(DocId docId, String branchName,
268: String languageName, boolean updateable,
269: AuthenticatedUser user) throws RepositoryException {
270: if (branchName == null || branchName.length() == 0)
271: throw new IllegalArgumentException(
272: "Null or empty branch name specified.");
273: if (languageName == null || languageName.length() == 0)
274: throw new IllegalArgumentException(
275: "Null or empty language name specified.");
276:
277: long branchId;
278: if (Character.isDigit(branchName.charAt(0))) {
279: try {
280: branchId = Long.parseLong(branchName);
281: } catch (NumberFormatException e) {
282: throw new RepositoryException("Invalid branch name: "
283: + branchName);
284: }
285: } else {
286: branchId = variantManager.getBranchByName(branchName,
287: false, user).getId();
288: }
289:
290: long languageId;
291: if (Character.isDigit(languageName.charAt(0))) {
292: try {
293: languageId = Long.parseLong(languageName);
294: } catch (NumberFormatException e) {
295: throw new RepositoryException("Invalid language name: "
296: + languageName);
297: }
298: } else {
299: languageId = variantManager.getLanguageByName(languageName,
300: false, user).getId();
301: }
302:
303: return getDocument(docId, branchId, languageId, updateable,
304: user);
305: }
306:
307: /**
308: * Note: it is important that all actual retrievals of AvailableVariants go through this method, as this method
309: * is overrided in the local implementation to get objects from the cache.
310: */
311: public AvailableVariants getAvailableVariants(DocId docId,
312: AuthenticatedUser user) throws RepositoryException {
313: return new AvailableVariantsImpl(documentStrategy
314: .getAvailableVariants(docId, user));
315: }
316:
317: public void deleteDocument(DocId docId, AuthenticatedUser user)
318: throws RepositoryException {
319: documentStrategy.deleteDocument(docId, user);
320: }
321:
322: public void deleteVariant(DocId docId, long branchId,
323: long languageId, AuthenticatedUser user)
324: throws RepositoryException {
325: documentStrategy.deleteVariant(docId, branchId, languageId,
326: user);
327: }
328:
329: public InputStream getBlob(DocId docId, long branchId,
330: long languageId, long versionId, long partTypeId,
331: AuthenticatedUser user) throws RepositoryException {
332: return documentStrategy.getBlob(docId, branchId, languageId,
333: versionId, partTypeId, user);
334: }
335:
336: public CommonCollectionManager getCollectionManager() {
337: return collectionManager;
338: }
339:
340: public void removeListener(RepositoryListener listener) {
341: listeners.remove(listener);
342: }
343:
344: public void addListener(RepositoryListener listener) {
345: listeners.add(listener);
346: }
347:
348: public void fireRepositoryEvent(RepositoryEventType type,
349: Object id, long updateCount) {
350: for (RepositoryListener listener : listeners) {
351: listener.repositoryEvent(type, id, updateCount);
352: }
353: }
354:
355: public ExtensionProvider getExtensionProvider(String extensionName) {
356: return extensions.get(extensionName);
357: }
358:
359: public CommonUserManager getUserManager() {
360: return userManager;
361: }
362:
363: public CommonNamespaceManager getNamespaceManager() {
364: return namespaceManager;
365: }
366:
367: public String getClientVersion(AuthenticatedUser user) {
368: return repositoryStrategy.getClientVersion(user);
369: }
370:
371: public String getServerVersion(AuthenticatedUser user) {
372: return repositoryStrategy.getServerVersion(user);
373: }
374:
375: public String normalizeDocumentId(String documentId) {
376: if (documentId == null)
377: throw new IllegalArgumentException(
378: "documentId argument is not allowed to be null");
379: Matcher matcher = Constants.DAISY_COMPAT_DOCID_PATTERN
380: .matcher(documentId);
381: if (matcher.matches()) {
382: String namespace = matcher.group(2);
383: if (namespace == null) {
384: String seqId = matcher.group(1);
385: namespace = getNamespaceManager()
386: .getRepositoryNamespace();
387: return seqId + "-" + namespace;
388: } else {
389: return documentId;
390: }
391: } else {
392: throw new InvalidDocumentIdException(
393: "Invalid document ID \"" + documentId + "\".");
394: }
395: }
396: }
|