KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > outerj > daisy > repository > commonimpl > DocumentVariantImpl


1 /*
2  * Copyright 2004 Outerthought bvba and Schaubroeck nv
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 package org.outerj.daisy.repository.commonimpl;
17
18 import org.outerj.daisy.repository.commonimpl.schema.CommonRepositorySchema;
19 import org.outerj.daisy.repository.*;
20 import org.outerj.daisy.repository.schema.*;
21 import org.outerx.daisy.x10.DocumentDocument;
22
23 import java.util.*;
24
25 /**
26  * Encapsulates all variant-specific data of a document.
27  * An instance of this class is contained by {@link DocumentImpl}.
28  */

29 public class DocumentVariantImpl {
30     private DocumentImpl ownerDocument;
31     private DocumentStrategy documentStrategy;
32     private CommonRepositorySchema repositorySchema;
33     private AuthenticatedUser currentUser;
34     /** The parts mapped by PartType ID (= Long object). */
35     private Map parts = new HashMap();
36     private boolean partChanges = false;
37     private long documentTypeId;
38     private boolean documentTypeChanged = false;
39     private String JavaDoc name;
40     private boolean nameUpdated = false;
41     private long branchId;
42     private long languageId;
43     private boolean isNew;
44     private Date lastModified;
45     private long lastModifier = -1;
46     private boolean retired = false;
47     private boolean retiredChanged = false;
48     private VersionImpl[] versions;
49     /** Cached reference to the live version. */
50     private Version liveVersion;
51     /** Indicates if the variable liveVersion has been initialiased. */
52     private boolean liveVersionLoaded = false;
53     /** Cached reference to the last version. */
54     private Version lastVersion;
55     /** Indicates if the variable lastVersion has been initialiased. */
56     private boolean lastVersionLoaded = false;
57     private long lastVersionId = -1;
58     private long liveVersionId = -1;
59     /** The fields mapped by FieldType ID (= Long object). */
60     private Map fields = new HashMap();
61     private boolean fieldChanges = false;
62     private List links = new ArrayList(3);
63     private boolean linkChanges = false;
64     private Map customFields = new HashMap();
65     private boolean customFieldChanges = false;
66     private Map documentCollections = new HashMap();
67     private boolean documentCollectionChanges = false;
68     private LockInfoImpl lockInfo = new LockInfoImpl();
69     private VersionState versionState = VersionState.PUBLISH;
70     private String JavaDoc summary;
71     private long updateCount = 0;
72     private IntimateAccess intimateAccess = new IntimateAccess();
73     private long createdFromBranchId = -1;
74     private long createdFromLanguageId = -1;
75     private long createdFromVersionId = -1;
76     // the variables below are values we need to store to be able to pass them on
77
// from the remote implementation
78
private boolean validateOnSave = true;
79     private long startBranchId;
80     private long startLanguageId;
81
82     public static final String JavaDoc ERROR_ACCESSING_REPOSITORY_SCHEMA = "Error accessing repository schema information.";
83     private static final String JavaDoc READ_ONLY_MESSAGE = "This document object is read-only.";
84
85     public DocumentVariantImpl(DocumentImpl ownerDocument, DocumentStrategy documentStrategy, CommonRepositorySchema repositorySchema, AuthenticatedUser currentUser, long documentTypeId, long branchId, long languageId) {
86         this.ownerDocument = ownerDocument;
87         this.documentStrategy = documentStrategy;
88         this.repositorySchema = repositorySchema;
89         this.currentUser = currentUser;
90         this.documentTypeId = documentTypeId;
91         this.branchId = branchId;
92         this.languageId = languageId;
93         this.isNew = true;
94     }
95
96     public DocumentVariantImpl.IntimateAccess getIntimateAccess(DocumentStrategy strategy) {
97         if (this.documentStrategy == strategy)
98             return intimateAccess;
99         return null;
100     }
101
102     public long getBranchId() {
103         return branchId;
104     }
105
106     public long getLanguageId() {
107         return languageId;
108     }
109
110     public boolean isNew() {
111         return isNew;
112     }
113
114     public long getDocumentTypeId() {
115         return documentTypeId;
116     }
117
118     public long getDocumentId() {
119         return ownerDocument.getId();
120     }
121
122     public void setValidateOnSave(boolean validateOnSave) {
123         this.validateOnSave = validateOnSave;
124     }
125
126     public void changeDocumentType(long documentTypeId) throws RepositoryException {
127         if (ownerDocument.isReadOnly())
128             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
129
130         if (documentTypeId != this.documentTypeId) {
131             // fetch the document type to be sure it exists
132
// the method below will throw an exception if it doesn't exist
133
repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser);
134
135             this.documentTypeId = documentTypeId;
136             this.documentTypeChanged = true;
137         }
138     }
139
140     public void changeDocumentType(String JavaDoc documentTypeName) throws RepositoryException {
141         if (ownerDocument.isReadOnly())
142             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
143
144         DocumentType documentType = repositorySchema.getDocumentTypeByName(documentTypeName, false, currentUser);
145         changeDocumentType(documentType.getId());
146     }
147
148     public Field getField(String JavaDoc name) throws FieldNotFoundException {
149         FieldType fieldType = null;
150         try {
151             fieldType = repositorySchema.getFieldTypeByName(name, false, currentUser);
152         } catch (RepositoryException e) {
153             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
154         }
155         return getField(fieldType.getId());
156     }
157
158     public Field getField(long fieldTypeId) throws FieldNotFoundException {
159         Field field = (Field)fields.get(new Long JavaDoc(fieldTypeId));
160         if (field == null)
161             throw new FieldNotFoundException(fieldTypeId);
162         else
163             return field;
164     }
165
166     public boolean hasField(long fieldTypeId) {
167         Field field = (Field)fields.get(new Long JavaDoc(fieldTypeId));
168         return field != null;
169     }
170
171     public boolean hasField(String JavaDoc fieldTypeName) {
172         FieldType fieldType = null;
173         try {
174             fieldType = repositorySchema.getFieldTypeByName(fieldTypeName, false, currentUser);
175         } catch (RepositoryException e) {
176             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
177         }
178         return hasField(fieldType.getId());
179     }
180
181     public Fields getFields() {
182         return new FieldsImpl((Field[])fields.values().toArray(new Field[0]));
183     }
184
185     public Fields getFieldsInOrder() {
186         return new FieldsImpl(orderFields((Field[])fields.values().toArray(new Field[0])));
187     }
188
189     public void setField(String JavaDoc name, Object JavaDoc value) throws DocumentTypeInconsistencyException {
190         if (ownerDocument.isReadOnly())
191             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
192
193         FieldType fieldType = null;
194         try {
195             fieldType = repositorySchema.getFieldTypeByName(name, false, currentUser);
196         } catch (RepositoryException e) {
197             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
198         }
199         setField(fieldType.getId(), value);
200     }
201
202     public void setField(long fieldTypeId, Object JavaDoc value) throws DocumentTypeInconsistencyException {
203         if (ownerDocument.isReadOnly())
204             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
205
206         if (value == null)
207             throw new NullPointerException JavaDoc("Field value cannot be null!");
208
209         DocumentType documentType = null;
210         try {
211             documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser);
212         } catch (RepositoryException e) {
213             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
214         }
215
216         FieldType fieldType;
217         try {
218             fieldType = repositorySchema.getFieldTypeById(fieldTypeId, false, currentUser);
219         } catch (RepositoryException e) {
220             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
221         }
222
223         if (!documentType.hasFieldType(fieldTypeId))
224             throw new DocumentTypeInconsistencyException("The FieldType \"" + fieldType.getName() + "\" (ID: " + fieldTypeId + ") is not allowed on this document.");
225
226         checkFieldValue(fieldType, value);
227
228         // Special handling for dates: make sure time component is reset
229
if (fieldType.getValueType() == ValueType.DATE) {
230             if (fieldType.isMultiValue()) {
231                 Object JavaDoc[] values = (Object JavaDoc[])value;
232                 for (int i = 0; i < values.length; i++)
233                     values[i] = getDate((Date)values[i]);
234             } else {
235                 value = getDate((Date)value);
236             }
237         } else if (fieldType.getValueType() == ValueType.DATETIME) {
238             if (fieldType.isMultiValue()) {
239                 Object JavaDoc[] values = (Object JavaDoc[])value;
240                 for (int i = 0; i < values.length; i++)
241                     values[i] = getDateTime((Date)values[i]);
242             } else {
243                 value = getDateTime((Date)value);
244             }
245         }
246
247         FieldImpl field = (FieldImpl)fields.get(new Long JavaDoc(fieldTypeId));
248
249         // if the value didn't change, don't update it
250
if (field != null && (fieldType.isMultiValue() ? Arrays.equals((Object JavaDoc[])field.getValue(), (Object JavaDoc[])value) : field.getValue().equals(value)))
251             return;
252
253         field = new FieldImpl(intimateAccess, fieldTypeId, value);
254         fields.put(new Long JavaDoc(fieldTypeId), field);
255         fieldChanges = true;
256     }
257
258     private Date getDate(Date date) {
259         Calendar calendar = new GregorianCalendar();
260         calendar.setTime(date);
261         calendar.set(Calendar.HOUR_OF_DAY, 0);
262         calendar.set(Calendar.MINUTE, 0);
263         calendar.set(Calendar.SECOND, 0);
264         calendar.set(Calendar.MILLISECOND, 0);
265         return calendar.getTime();
266     }
267
268     private Date getDateTime(Date date) {
269         Calendar calendar = new GregorianCalendar();
270         calendar.setTime(date);
271         calendar.set(Calendar.MILLISECOND, 0);
272         return calendar.getTime();
273     }
274
275     private void checkFieldValue(FieldType fieldType, Object JavaDoc value) throws DocumentTypeInconsistencyException {
276         ValueType valueType = fieldType.getValueType();
277         if (fieldType.isMultiValue()) {
278             if (!value.getClass().isArray())
279                 throw new DocumentTypeInconsistencyException("The value for the multivalue-field \"" + fieldType.getName() + "\" should be an array.");
280             Object JavaDoc[] values = (Object JavaDoc[])value;
281             if (values.length == 0)
282                 throw new DocumentTypeInconsistencyException("The value supplied for the multivalue field \"" + fieldType.getName() + "\" is a zero-length array, it should be an array of at least one element.");
283             for (int i = 0; i < values.length; i++) {
284                 if (!valueType.getTypeClass().isAssignableFrom(values[i].getClass()))
285                     throw new DocumentTypeInconsistencyException("The supplied value for the multivalue field \"" + fieldType.getName() + "\" at index " + i + " is not of the correct type. Expected was a " + valueType.toString() + " (" + valueType.getTypeClass().getName() + ") but got a " + value.getClass().getName());
286             }
287         } else {
288             if (!valueType.getTypeClass().isAssignableFrom(value.getClass()))
289                 throw new DocumentTypeInconsistencyException("The supplied value for the field \"" + fieldType.getName() + "\" is not of the correct type. Expected was a " + valueType.toString() + " (" + valueType.getTypeClass().getName() + ") but got a " + value.getClass().getName());
290         }
291     }
292
293     public void deleteField(String JavaDoc name) {
294         if (ownerDocument.isReadOnly())
295             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
296
297         FieldType fieldType = null;
298         try {
299             fieldType = repositorySchema.getFieldTypeByName(name, false, currentUser);
300         } catch (RepositoryException e) {
301             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
302         }
303         deleteField(fieldType.getId());
304     }
305
306     public void deleteField(long fieldTypeId) {
307         if (ownerDocument.isReadOnly())
308             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
309
310         Long JavaDoc key = new Long JavaDoc(fieldTypeId);
311         if (fields.containsKey(key)) {
312             fields.remove(new Long JavaDoc(fieldTypeId));
313             fieldChanges = true;
314         }
315     }
316
317     public LockInfo getLockInfo(boolean fresh) throws RepositoryException {
318         LockInfoImpl lockInfo = this.lockInfo;
319         if ((fresh || lockInfo == null) && !isNew) {
320             synchronized(this) {
321                 lockInfo = documentStrategy.getLockInfo(this);
322                 this.lockInfo = lockInfo;
323             }
324         }
325         return lockInfo;
326     }
327
328     // This method is by purpose not in the Document interface. It is used to clear lock
329
// info in cached document objects. If it would be in the interface, then the method
330
// getLockInfo should cover the case where lockInfo is null and id is -1.
331
public void clearLockInfo() {
332         this.lockInfo = null;
333     }
334
335     public boolean lock(long duration, LockType lockType) throws RepositoryException {
336         if (ownerDocument.isReadOnly())
337             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
338
339         if (isNew)
340             throw new RepositoryException("Can't take a lock on a new, non-saved document variant.");
341
342         lockInfo = documentStrategy.lock(this, duration, lockType);
343
344         if (!lockInfo.hasLock())
345             return false;
346
347         return lockInfo.getUserId() == currentUser.getId();
348     }
349
350     public boolean releaseLock() throws RepositoryException {
351         if (ownerDocument.isReadOnly())
352             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
353
354         if (isNew)
355             return true;
356
357         lockInfo = documentStrategy.releaseLock(this);
358         return !lockInfo.hasLock();
359     }
360
361     public void addXml(DocumentDocument.Document documentXml) throws RepositoryException {
362         addNonVersionedDataToXml(documentXml);
363
364         documentXml.setDataVersionId(-1); // -1 indicates "current data in object, whether it's saved or not"
365
documentXml.setName(name);
366         documentXml.setFields(getFieldsInOrder().getXml().getFields());
367         documentXml.setParts(getPartsInOrder().getXml().getParts());
368         documentXml.setLinks(getLinks().getXml().getLinks());
369         documentXml.setValidateOnSave(validateOnSave);
370     }
371
372     public void addXml(DocumentDocument.Document documentXml, long versionId) throws RepositoryException {
373         Version version = getVersion(versionId);
374         addNonVersionedDataToXml(documentXml);
375
376         documentXml.setDataVersionId(versionId);
377         documentXml.setName(version.getDocumentName());
378         documentXml.setFields(version.getFieldsInOrder().getXml().getFields());
379         documentXml.setParts(version.getPartsInOrder().getXml().getParts());
380         documentXml.setLinks(version.getLinks().getXml().getLinks());
381     }
382
383     public void addNonVersionedDataToXml(DocumentDocument.Document documentXml) {
384         if (!isNew) {
385             GregorianCalendar lastModified = new GregorianCalendar();
386             lastModified.setTime(this.lastModified);
387             documentXml.setVariantLastModified(lastModified);
388             documentXml.setVariantLastModifier(lastModifier);
389             if (liveVersionId != -1)
390                 documentXml.setLiveVersionId(liveVersionId);
391         }
392
393         documentXml.setBranchId(branchId);
394         documentXml.setLanguageId(languageId);
395         documentXml.setTypeId(documentTypeId);
396         documentXml.setLastVersionId(lastVersionId);
397         documentXml.setRetired(retired);
398         documentXml.setNewVersionState(DocumentDocument.Document.NewVersionState.Enum.forString(versionState.toString()));
399         documentXml.setVariantUpdateCount(updateCount);
400         if (summary != null)
401             documentXml.setSummary(summary);
402         documentXml.setCreatedFromBranchId(createdFromBranchId);
403         documentXml.setCreatedFromLanguageId(createdFromLanguageId);
404         documentXml.setCreatedFromVersionId(createdFromVersionId);
405
406         DocumentDocument.Document.CustomFields customFieldsXml = documentXml.addNewCustomFields();
407         Iterator customFieldsIt = customFields.entrySet().iterator();
408         while (customFieldsIt.hasNext()) {
409             Map.Entry customField = (Map.Entry)customFieldsIt.next();
410             DocumentDocument.Document.CustomFields.CustomField customFieldXml = customFieldsXml.addNewCustomField();
411             customFieldXml.setName((String JavaDoc)customField.getKey());
412             customFieldXml.setValue((String JavaDoc)customField.getValue());
413         }
414
415         LockInfo lockInfo;
416         try {
417             lockInfo = getLockInfo(false);
418         } catch (RepositoryException e) {
419             throw new RuntimeException JavaDoc(e);
420         }
421         documentXml.setLockInfo(lockInfo.getXml().getLockInfo());
422
423         long[] collectionIds = new long[documentCollections.size()];
424         Iterator collectionsIt = documentCollections.values().iterator();
425         int i = 0;
426         while (collectionsIt.hasNext()) {
427             DocumentCollection collection = (DocumentCollection)collectionsIt.next();
428             collectionIds[i] = collection.getId();
429             i++;
430         }
431         documentXml.addNewCollectionIds().setCollectionIdArray(collectionIds);
432     }
433
434     public void setName(String JavaDoc name) {
435         if (ownerDocument.isReadOnly())
436             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
437
438         if (name == null)
439             throw new NullPointerException JavaDoc("name may not be null.");
440
441         if (!name.equals(this.name)) {
442             this.name = name;
443             nameUpdated = true;
444         }
445     }
446
447     public String JavaDoc getName() {
448         return name;
449     }
450
451     public void setPart(String JavaDoc partTypeName, String JavaDoc mimeType, byte[] data) throws DocumentTypeInconsistencyException {
452         if (ownerDocument.isReadOnly())
453             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
454
455         if (data == null)
456             throw new NullPointerException JavaDoc("data argument cannot be null.");
457
458         setPart(partTypeName, mimeType, new ByteArrayPartDataSource(data));
459
460     }
461
462     public void setPart(long partTypeId, String JavaDoc mimeType, byte[] data) throws DocumentTypeInconsistencyException {
463         if (ownerDocument.isReadOnly())
464             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
465
466         if (data == null)
467             throw new NullPointerException JavaDoc("data argument cannot be null.");
468
469         setPart(partTypeId, mimeType, new ByteArrayPartDataSource(data));
470     }
471
472     public void setPart(String JavaDoc partTypeName, String JavaDoc mimeType, PartDataSource partDataSource) throws DocumentTypeInconsistencyException {
473         if (ownerDocument.isReadOnly())
474             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
475
476         PartType partType = null;
477         try {
478             partType = repositorySchema.getPartTypeByName(partTypeName, false, currentUser);
479         } catch (RepositoryException e) {
480             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
481         }
482
483         setPart(partType.getId(), mimeType, partDataSource);
484     }
485
486     public void setPart(long partTypeId, String JavaDoc mimeType, PartDataSource partDataSource) throws DocumentTypeInconsistencyException {
487         if (ownerDocument.isReadOnly())
488             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
489
490         // first check with the DocumentType if this part is allowed
491
DocumentType documentType;
492         try {
493             documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser);
494         } catch (RepositoryException e) {
495             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
496         }
497
498         PartType partType;
499         try {
500             partType = repositorySchema.getPartTypeById(partTypeId, false, currentUser);
501         } catch (RepositoryException e) {
502             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
503         }
504
505         if (mimeType == null || mimeType.length() == 0)
506             throw new NullPointerException JavaDoc("mimeType argument cannot be null or an empty string");
507
508         if (partDataSource == null)
509             throw new NullPointerException JavaDoc("partDataSource argument cannot be null.");
510
511         if (!documentType.hasPartType(partTypeId))
512             throw new DocumentTypeInconsistencyException("The PartType \"" + partType.getName() + "\" (ID: " + partTypeId + ") is not allowed on this document.");
513
514         if (!partType.mimeTypeAllowed(mimeType))
515             throw new DocumentTypeInconsistencyException("The mime-type \"" + mimeType + "\" isn't part of the allowed mime types (" + partType.getMimeTypes() + ") required by the PartType \"" + partType.getName() + "\" (ID: " + partTypeId + ").");
516
517         PartImpl part = new PartImpl(intimateAccess, partTypeId, lastVersionId);
518         PartImpl.IntimateAccess partInt = part.getIntimateAccess(documentStrategy);
519         partInt.setMimeType(mimeType);
520         partInt.setData(partDataSource);
521         partInt.setNewOrUpdated(true, true);
522
523         parts.put(new Long JavaDoc(partTypeId), part);
524         partChanges = true;
525     }
526
527     public void setPartFileName(String JavaDoc partTypeName, String JavaDoc fileName) {
528         if (ownerDocument.isReadOnly())
529             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
530
531         PartType partType = null;
532         try {
533             partType = repositorySchema.getPartTypeByName(partTypeName, false, currentUser);
534         } catch (RepositoryException e) {
535             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
536         }
537
538         setPartFileName(partType.getId(), fileName);
539     }
540
541     public void setPartFileName(long partTypeId, String JavaDoc fileName) {
542         if (ownerDocument.isReadOnly())
543             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
544
545         PartImpl part = (PartImpl)parts.get(new Long JavaDoc(partTypeId));
546         if (part == null)
547             throw new RepositoryRuntimeException("The document does not have a part for part type ID " + partTypeId);
548
549         if ((part.getFileName() == null && fileName == null) || (part.getFileName() != null && part.getFileName().equals(fileName)))
550             return;
551
552         PartImpl.IntimateAccess partInt = part.getIntimateAccess(documentStrategy);
553         partInt.setFileName(fileName);
554         partInt.setNewOrUpdated(true, partInt.isDataUpdated());
555         partChanges = true;
556     }
557
558     public void setPartMimeType(String JavaDoc partTypeName, String JavaDoc mimeType) {
559         if (ownerDocument.isReadOnly())
560             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
561
562         PartType partType = null;
563         try {
564             partType = repositorySchema.getPartTypeByName(partTypeName, false, currentUser);
565         } catch (RepositoryException e) {
566             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
567         }
568
569         setPartMimeType(partType.getId(), mimeType);
570     }
571
572     public void setPartMimeType(long partTypeId, String JavaDoc mimeType) {
573         if (ownerDocument.isReadOnly())
574             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
575
576         if (mimeType == null)
577             throw new IllegalArgumentException JavaDoc("Part mime-type cannot be set to null value.");
578
579         PartImpl part = (PartImpl)parts.get(new Long JavaDoc(partTypeId));
580         if (part == null)
581             throw new RepositoryRuntimeException("The document does not have a part for part type ID " + partTypeId);
582
583         if (part.getMimeType().equals(mimeType))
584             return;
585
586         PartImpl.IntimateAccess partInt = part.getIntimateAccess(documentStrategy);
587         partInt.setMimeType(mimeType);
588         partInt.setNewOrUpdated(true, partInt.isDataUpdated());
589         partChanges = true;
590     }
591
592     public Parts getParts() {
593         return new PartsImpl((Part[])parts.values().toArray(new Part[0]));
594     }
595
596     public Parts getPartsInOrder() {
597         return new PartsImpl(orderParts((Part[])parts.values().toArray(new Part[0])));
598     }
599
600     private Part[] orderParts(Part[] parts) {
601         Part[] resultList = new Part[parts.length];
602         boolean[] handled = new boolean[parts.length];
603
604         DocumentType documentType = null;
605         try {
606             documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser);
607         } catch (RepositoryException e) {
608             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
609         }
610         PartTypeUse[] partTypeUses = documentType.getPartTypeUses();
611
612         int resultListPos = -1;
613         for (int i = 0; i < partTypeUses.length; i++) {
614             long id = partTypeUses[i].getPartType().getId();
615             for (int k = 0; k < parts.length; k++) {
616                 if (parts[k].getTypeId() == id) {
617                     handled[k] = true;
618                     resultListPos++;
619                     resultList[resultListPos] = parts[k];
620                     break;
621                 }
622             }
623         }
624
625         for (int i = 0; i < handled.length; i++) {
626             if (!handled[i]) {
627                 resultListPos++;
628                 resultList[resultListPos] = parts[i];
629             }
630         }
631
632         return resultList;
633     }
634
635     private Field[] orderFields(Field[] fields) {
636         Field[] resultList = new Field[fields.length];
637         boolean[] handled = new boolean[fields.length];
638
639         DocumentType documentType = null;
640         try {
641             documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser);
642         } catch (RepositoryException e) {
643             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
644         }
645         FieldTypeUse[] fieldTypeUses = documentType.getFieldTypeUses();
646
647         int resultListPos = -1;
648         for (int i = 0; i < fieldTypeUses.length; i++) {
649             long id = fieldTypeUses[i].getFieldType().getId();
650             for (int k = 0; k < fields.length; k++) {
651                 if (fields[k].getTypeId() == id) {
652                     handled[k] = true;
653                     resultListPos++;
654                     resultList[resultListPos] = fields[k];
655                     break;
656                 }
657             }
658         }
659
660         for (int i = 0; i < handled.length; i++) {
661             if (!handled[i]) {
662                 resultListPos++;
663                 resultList[resultListPos] = fields[i];
664             }
665         }
666
667         return resultList;
668     }
669
670     public void deletePart(long partTypeId) {
671         if (ownerDocument.isReadOnly())
672             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
673
674         Long JavaDoc key = new Long JavaDoc(partTypeId);
675         if (parts.containsKey(key)) {
676             parts.remove(key);
677             partChanges = true;
678         }
679     }
680
681     public void deletePart(String JavaDoc name) {
682         if (ownerDocument.isReadOnly())
683             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
684
685         PartType partType = null;
686         try {
687             partType = repositorySchema.getPartTypeByName(name, false, currentUser);
688         } catch (RepositoryException e) {
689             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
690         }
691         deletePart(partType.getId());
692     }
693
694     public Part getPart(long partTypeId) throws PartNotFoundException {
695         Part part = (Part)parts.get(new Long JavaDoc(partTypeId));
696         if (part == null)
697             throw new PartNotFoundException(partTypeId);
698         else
699             return part;
700     }
701
702     public Part getPart(String JavaDoc name) throws PartNotFoundException {
703         PartType partType = null;
704         try {
705             partType = repositorySchema.getPartTypeByName(name, false, currentUser);
706         } catch (RepositoryException e) {
707             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
708         }
709         return getPart(partType.getId());
710     }
711
712     public boolean hasPart(long partTypeId) {
713         Part part = (Part)parts.get(new Long JavaDoc(partTypeId));
714         return part != null;
715     }
716
717     public boolean hasPart(String JavaDoc name) {
718         PartType partType = null;
719         try {
720             partType = repositorySchema.getPartTypeByName(name, false, currentUser);
721         } catch (RepositoryException e) {
722             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA, e);
723         }
724         return hasPart(partType.getId());
725     }
726
727     public void setCustomField(String JavaDoc name, String JavaDoc value) {
728         if (ownerDocument.isReadOnly())
729             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
730
731         if (name == null)
732             throw new RuntimeException JavaDoc("name argument cannot be null.");
733         if (value == null)
734             throw new RuntimeException JavaDoc("value argument cannot be null.");
735
736         customFields.put(name, value);
737         customFieldChanges = true;
738     }
739
740     public void deleteCustomField(String JavaDoc name) {
741         if (ownerDocument.isReadOnly())
742             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
743
744         if (name == null)
745             throw new RuntimeException JavaDoc("name argument cannot be null.");
746
747         customFields.remove(name);
748         customFieldChanges = true;
749     }
750
751     public void clearCustomFields() {
752         if (ownerDocument.isReadOnly())
753             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
754
755         customFields.clear();
756         customFieldChanges = true;
757     }
758
759     public void clearCollections() {
760         if (ownerDocument.isReadOnly())
761             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
762
763         documentCollections.clear();
764         documentCollectionChanges = true;
765     }
766
767     public Map getCustomFields() {
768         return new HashMap(customFields);
769     }
770
771     public String JavaDoc getCustomField(String JavaDoc name) {
772         if (name == null)
773             throw new NullPointerException JavaDoc("name argument cannot be null.");
774
775         return (String JavaDoc)customFields.get(name);
776     }
777
778     public boolean hasCustomField(String JavaDoc name) {
779         if (name == null)
780             throw new NullPointerException JavaDoc("name argument cannot be null.");
781
782         return customFields.containsKey(name);
783     }
784
785     public Links getLinks() {
786         return new LinksImpl((Link[])links.toArray(new Link[links.size()]));
787     }
788
789     public void addLink(String JavaDoc title, String JavaDoc target) {
790         if (ownerDocument.isReadOnly())
791             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
792
793         links.add(new LinkImpl(title, target));
794         linkChanges = true;
795     }
796
797     public void deleteLink(int index) {
798         if (ownerDocument.isReadOnly())
799             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
800
801         links.remove(index);
802         linkChanges = true;
803     }
804
805     public void clearLinks() {
806         if (ownerDocument.isReadOnly())
807             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
808
809         links.clear();
810         linkChanges = true;
811     }
812
813     public void validate() throws DocumentTypeInconsistencyException {
814         fullConsistencyCheck();
815     }
816
817     public void setNewVersionState(VersionState versionState) {
818         if (versionState == null)
819             throw new NullPointerException JavaDoc("versionState argument cannot be null.");
820
821         this.versionState = versionState;
822     }
823
824     public VersionState getNewVersionState() {
825         return versionState;
826     }
827
828     public synchronized Version getVersion(long versionId) throws RepositoryException {
829         if (isNew)
830             throw new RepositoryException("A new document variant has no versions.");
831         if (versionId < 1 || versionId > lastVersionId)
832             throw new RepositoryException("Document with ID " + ownerDocument.getId() + " (branch: " + branchId + ", language: " + languageId + ") does not have a version " + versionId);
833
834         checkVersionsArray();
835
836         int arrayPos = (int)versionId - 1;
837         if (versions[arrayPos] == null) {
838             versions[arrayPos] = documentStrategy.loadVersion(this, versionId);
839         }
840
841         return versions[arrayPos];
842     }
843
844     public Version getLastVersion() throws RepositoryException {
845         if (isNew)
846             return null;
847
848         if (lastVersionLoaded)
849             return lastVersion;
850
851         Version[] versions = getVersions().getArray();
852         lastVersion = versions[versions.length - 1];
853         lastVersionLoaded = true;
854         return lastVersion;
855     }
856
857     public Version getLiveVersion() throws RepositoryException {
858         if (isNew || liveVersionId == -1)
859             return null;
860
861         if (liveVersionLoaded)
862             return liveVersion;
863
864         checkVersionsArray();
865         int liveVersionPos = (int)liveVersionId - 1; // position in the versions array
866
if (versions[(int)liveVersionId - 1] != null) {
867             liveVersion = versions[liveVersionPos];
868         } else {
869             VersionImpl newLiveVersion = documentStrategy.loadVersion(this, liveVersionId);
870             versions[liveVersionPos] = newLiveVersion;
871             liveVersion = newLiveVersion;
872         }
873         liveVersionLoaded = true;
874         return liveVersion;
875     }
876
877     public long getLiveVersionId() {
878         return liveVersionId;
879     }
880
881     public synchronized Versions getVersions() throws RepositoryException {
882         if (isNew)
883             return new VersionsImpl(new Version[0]);
884
885         loadVersions();
886
887         return new VersionsImpl((Version[])versions.clone());
888     }
889
890     private void loadVersions() throws RepositoryException {
891         checkVersionsArray();
892
893         VersionImpl[] loadedVersions = null;
894
895         // check if all versions are loaded, if not load them
896
// note that we don't simply replace the whole version array because some
897
// versions may already be loaded fully, and otherwise that work would be lost.
898
for (int i = 0; i < versions.length; i++) {
899             if (versions[i] == null) {
900                 if (loadedVersions == null)
901                     loadedVersions = documentStrategy.loadShallowVersions(this);
902                 versions[i] = loadedVersions[i];
903             }
904         }
905     }
906
907     public long getLastVersionId() {
908         return lastVersionId;
909     }
910
911     private final void checkVersionsArray() {
912         if (versions == null) {
913             versions = new VersionImpl[(int)lastVersionId];
914         } else if (versions.length != lastVersionId) {
915             VersionImpl[] oldVersions = versions;
916             versions = new VersionImpl[(int)lastVersionId];
917             System.arraycopy(oldVersions, 0, versions, 0, oldVersions.length);
918         }
919     }
920
921     private void fullConsistencyCheck() throws DocumentTypeInconsistencyException {
922         DocumentType documentType = null;
923         try {
924             documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser);
925         } catch (RepositoryException e) {
926             throw new RuntimeException JavaDoc(ERROR_ACCESSING_REPOSITORY_SCHEMA);
927         }
928
929         // check the parts
930
PartTypeUse[] partTypeUses = documentType.getPartTypeUses();
931         boolean[] hasPartType = new boolean[partTypeUses.length];
932
933         Part[] parts = getParts().getArray();
934         for (int i = 0; i < parts.length; i++) {
935             long partTypeId = parts[i].getTypeId();
936             int partTypeIndex = -1;
937             for (int j = 0; j < partTypeUses.length; j++) {
938                 if (partTypeUses[j].getPartType().getId() == partTypeId) {
939                     partTypeIndex = j;
940                 }
941             }
942             if (partTypeIndex == -1)
943                 throw new DocumentTypeInconsistencyException("The document contains a not-allowed part (PartType ID: " + partTypeId + ").");
944             hasPartType[partTypeIndex] = true;
945             if (!partTypeUses[partTypeIndex].getPartType().mimeTypeAllowed(parts[i].getMimeType()))
946                 throw new DocumentTypeInconsistencyException("The mime-type for the part \"" + partTypeUses[partTypeIndex].getPartType().getName() + "\" isn't part of the allowed mime types (PartType ID: " + partTypeId + ").");
947         }
948
949         for (int i = 0; i < partTypeUses.length; i++) {
950             if (partTypeUses[i].isRequired() && !hasPartType[i])
951                 throw new DocumentTypeInconsistencyException("The document doesn't have the required part \"" + partTypeUses[i].getPartType().getName() + "\" (ID: " + partTypeUses[i].getPartType().getId() + ").");
952         }
953
954         // check the fields
955
FieldTypeUse[] fieldTypeUses = documentType.getFieldTypeUses();
956         boolean[] hasFieldType = new boolean[fieldTypeUses.length];
957
958         Field[] fields = getFields().getArray();
959         for (int i = 0; i < fields.length; i++) {
960             long fieldTypeId = fields[i].getTypeId();
961             int fieldTypeIndex = -1;
962             for (int j = 0; j < fieldTypeUses.length; j++) {
963                 if (fieldTypeUses[j].getFieldType().getId() == fieldTypeId) {
964                     fieldTypeIndex = j;
965                 }
966             }
967             if (fieldTypeIndex == -1)
968                 throw new DocumentTypeInconsistencyException("The document contains a not-allowed field (FieldType ID: " + fieldTypeId + ").");
969             hasFieldType[fieldTypeIndex] = true;
970
971             FieldType fieldType = fieldTypeUses[fieldTypeIndex].getFieldType();
972             checkFieldValue(fieldType, fields[i].getValue());
973         }
974
975         for (int i = 0; i < fieldTypeUses.length; i++) {
976             if (fieldTypeUses[i].isRequired() && !hasFieldType[i])
977                 throw new DocumentTypeInconsistencyException("The document doesn't have the required field \"" + fieldTypeUses[i].getFieldType().getName() + "\" (ID: " + fieldTypeUses[i].getFieldType().getId() + ").");
978         }
979     }
980
981     public Date getLastModified() {
982         if (lastModified != null)
983             return (Date)lastModified.clone();
984         else
985             return lastModified;
986     }
987
988     public long getLastModifier() {
989         return lastModifier;
990     }
991
992     public boolean isRetired() {
993         return retired;
994     }
995
996     public void setRetired(boolean retired) {
997         if (ownerDocument.isReadOnly())
998             throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
999
1000        if (retired != this.retired) {
1001            this.retired = retired;
1002            this.retiredChanged = true;
1003        }
1004    }
1005
1006    public DocumentCollections getCollections() {
1007        return new DocumentCollectionsImpl(
1008                (DocumentCollection[])documentCollections.values().toArray(
1009                        new DocumentCollection[documentCollections.size()]));
1010    }
1011
1012    public boolean inCollection(DocumentCollection collection) {
1013        return documentCollections.containsKey(new Long JavaDoc(collection.getId()));
1014    }
1015
1016    public boolean inCollection(long collectionId) {
1017        return documentCollections.containsKey(new Long JavaDoc(collectionId));
1018    }
1019
1020    public void addToCollection(DocumentCollection c) {
1021        if (ownerDocument.isReadOnly())
1022            throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
1023
1024        if (c.getId() == -1)
1025            throw new IllegalArgumentException JavaDoc("The specified collection has not yet been saved.");
1026
1027        this.documentCollectionChanges = true;
1028        this.documentCollections.put(new Long JavaDoc(c.getId()), c);
1029    }
1030
1031    public void removeFromCollection(DocumentCollection c) {
1032        if (ownerDocument.isReadOnly())
1033            throw new RuntimeException JavaDoc(READ_ONLY_MESSAGE);
1034
1035        this.documentCollectionChanges = true;
1036        documentCollections.remove(new Long JavaDoc(c.getId()));
1037    }
1038
1039    public String JavaDoc getSummary() {
1040        return summary == null ? "" : summary;
1041    }
1042
1043    public long getUpdateCount() {
1044        return updateCount;
1045    }
1046
1047    public long getCreatedFromBranchId() {
1048        return createdFromBranchId;
1049    }
1050
1051    public long getCreatedFromLanguageId() {
1052        return createdFromLanguageId;
1053    }
1054
1055    public long getCreatedFromVersionId() {
1056        return createdFromVersionId;
1057    }
1058
1059    /**
1060     * Checks whether this document needs a new version. This is the case when:
1061     */

1062    public boolean needsNewVersion() {
1063        // a new document always needs an initial version
1064
if (isNew)
1065            return true;
1066
1067        if (nameUpdated || fieldChanges || linkChanges || partChanges)
1068            return true;
1069
1070        return false;
1071    }
1072
1073    public boolean needsSaving() {
1074        boolean nonVersionedChanges = documentCollectionChanges || customFieldChanges || documentTypeChanged || retiredChanged;
1075        if (nonVersionedChanges)
1076            return true;
1077        else
1078            return needsNewVersion();
1079    }
1080
1081    public class IntimateAccess {
1082
1083        private IntimateAccess() {
1084        }
1085
1086        public void setLockInfo(LockInfoImpl lockInfo) {
1087            DocumentVariantImpl.this.lockInfo = lockInfo;
1088        }
1089
1090        public long getLastVersionId() {
1091            return lastVersionId;
1092        }
1093
1094        public boolean hasCustomFieldChanges() {
1095            return customFieldChanges;
1096        }
1097
1098        public void setIsNew(boolean isNew) {
1099            DocumentVariantImpl.this.isNew = isNew;
1100        }
1101
1102        public boolean isNameUpdated() {
1103            return nameUpdated;
1104        }
1105
1106        public boolean hasFieldChanges() {
1107            return fieldChanges;
1108        }
1109
1110        public boolean hasLinkChanges() {
1111            return linkChanges;
1112        }
1113
1114        public boolean hasPartChanges() {
1115            return partChanges;
1116        }
1117
1118        public boolean hasCollectionChanges() {
1119            return documentCollectionChanges;
1120        }
1121
1122        /**
1123         * Intialises required fields when loading an existing document variant.
1124         */

1125        public void load(long documentTypeId, boolean retired, long lastVersionId, long liveVersionId,
1126                Date lastModified, long lastModifier, long createdFromBranchId, long createdFromLanguageId,
1127                long createdFromVersionId, long updateCount) {
1128            DocumentVariantImpl.this.documentTypeId = documentTypeId;
1129            DocumentVariantImpl.this.retired = retired;
1130            DocumentVariantImpl.this.lastVersionId = lastVersionId;
1131            DocumentVariantImpl.this.liveVersionId = liveVersionId;
1132            DocumentVariantImpl.this.lastModified = lastModified;
1133            DocumentVariantImpl.this.lastModifier = lastModifier;
1134            DocumentVariantImpl.this.createdFromBranchId = createdFromBranchId;
1135            DocumentVariantImpl.this.createdFromLanguageId = createdFromLanguageId;
1136            DocumentVariantImpl.this.createdFromVersionId = createdFromVersionId;
1137            DocumentVariantImpl.this.updateCount = updateCount;
1138            isNew = false;
1139        }
1140
1141        /**
1142         * Updates the state of this Document object after saving it, also resets
1143         * all 'dirty' flags.
1144         */

1145        public void saved(long lastVersionId, long liveVersionId, Date lastModified, String JavaDoc summary, long updateCount) {
1146            DocumentVariantImpl.this.lastVersionId = lastVersionId;
1147            DocumentVariantImpl.this.liveVersionId = liveVersionId;
1148            DocumentVariantImpl.this.lastModified = lastModified;
1149            DocumentVariantImpl.this.lastModifier = currentUser.getId();
1150            DocumentVariantImpl.this.updateCount = updateCount;
1151            DocumentVariantImpl.this.summary = summary;
1152
1153            nameUpdated = false;
1154            partChanges = false;
1155            linkChanges = false;
1156            documentCollectionChanges = false;
1157
1158            PartImpl[] parts = getPartImpls();
1159            for (int i = 0; i < parts.length; i++) {
1160                PartImpl.IntimateAccess partInt = parts[i].getIntimateAccess(documentStrategy);
1161                partInt.setNewOrUpdated(false, false);
1162                partInt.setData(null);
1163                partInt.setVersionId(lastVersionId);
1164            }
1165            fieldChanges = false;
1166            customFieldChanges = false;
1167
1168            // last/live version might have changed
1169
liveVersion = null;
1170            liveVersionLoaded = false;
1171            lastVersion = null;
1172            lastVersionLoaded = false;
1173            isNew = false;
1174            retiredChanged = false;
1175            documentTypeChanged = false;
1176        }
1177
1178        public DocumentStrategy getDocumentStrategy() {
1179            return documentStrategy;
1180        }
1181
1182        public AuthenticatedUser getCurrentUser() {
1183            return currentUser;
1184        }
1185
1186        /**
1187         * Sets a user field without marking the user fields as modified.
1188         */

1189        public void setCustomField(String JavaDoc name, String JavaDoc value) {
1190            customFields.put(name, value);
1191        }
1192
1193        public PartImpl[] getPartImpls() {
1194            return (PartImpl[])parts.values().toArray(new PartImpl[0]);
1195        }
1196
1197        public DocumentCollectionImpl[] getDocumentCollectionImpls() {
1198            return (DocumentCollectionImpl[])
1199                documentCollections.values().toArray(new DocumentCollectionImpl[0]);
1200        }
1201
1202
1203        public void addPart(PartImpl part) {
1204            parts.put(new Long JavaDoc(part.getTypeId()), part);
1205        }
1206
1207        /**
1208         * Adds a link without marking the links as being modified.
1209         */

1210        public void addLink(LinkImpl link) {
1211            links.add(link);
1212        }
1213
1214        /**
1215         * Sets the name of the document without altering the "name dirty" flag.
1216         */

1217        public void setName(String JavaDoc name) {
1218            if (name == null)
1219                throw new NullPointerException JavaDoc("name may not be null.");
1220            DocumentVariantImpl.this.name = name;
1221        }
1222
1223        /**
1224         * Adds the given field. This method will not change the flag indicating
1225         * whether there were field changes.
1226         */

1227        public void addField(FieldImpl field) {
1228            fields.put(new Long JavaDoc(field.getTypeId()), field);
1229        }
1230
1231        public DocumentImpl getDocument() {
1232            return ownerDocument;
1233        }
1234
1235        public CommonRepositorySchema getRepositorySchema() {
1236            return repositorySchema;
1237        }
1238
1239        /**
1240         * Adds the specified collection. This method will not change the flag indicating
1241         * whether there were collection changes.
1242         */

1243        public void addCollection(DocumentCollectionImpl collection) {
1244            documentCollections.put(new Long JavaDoc(collection.getId()), collection);
1245        }
1246
1247        public Part[] orderParts(Part[] parts) {
1248            return DocumentVariantImpl.this.orderParts(parts);
1249        }
1250
1251        public Field[] orderFields(Field[] fields) {
1252            return DocumentVariantImpl.this.orderFields(fields);
1253        }
1254
1255        public void setSummary(String JavaDoc summary) {
1256            DocumentVariantImpl.this.summary = summary;
1257        }
1258
1259        public DocumentVariantImpl getVariant() {
1260            return DocumentVariantImpl.this;
1261        }
1262
1263        public void setCreatedFrom(long branchId, long languageId, long versionId) {
1264            createdFromBranchId = branchId;
1265            createdFromLanguageId = languageId;
1266            createdFromVersionId = versionId;
1267        }
1268
1269        public void setStartFrom(long branchId, long languageId) {
1270            startBranchId = branchId;
1271            startLanguageId = languageId;
1272        }
1273
1274        public long getStartBranchId() {
1275            return startBranchId;
1276        }
1277
1278        public long getStartLanguageId() {
1279            return startLanguageId;
1280        }
1281    }
1282}
1283
Popular Tags