KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > content > ContentObject


1 //
2
// ____.
3
// __/\ ______| |__/\. _______
4
// __ .____| | \ | +----+ \
5
// _______| /--| | | - \ _ | : - \_________
6
// \\______: :---| : : | : | \________>
7
// |__\---\_____________:______: :____|____:_____\
8
// /_____|
9
//
10
// . . . i n j a h i a w e t r u s t . . .
11
//
12

13 package org.jahia.content;
14
15 import java.util.*;
16
17 import org.jahia.exceptions.*;
18 import org.jahia.params.*;
19 import org.jahia.services.acl.*;
20 import org.jahia.services.pages.ContentPage;
21 import org.jahia.services.sites.JahiaSite;
22 import org.jahia.services.sites.SiteLanguageSettings;
23 import org.jahia.services.usermanager.*;
24 import org.jahia.services.version.*;
25 import org.jahia.bin.Jahia;
26 import org.jahia.content.events.ContentActivationEvent;
27 import org.jahia.registries.ServicesRegistry;
28
29 /**
30  * This class is the main content model class, from which all the other
31  * content classes derive. It contains information about version,
32  * locking, language, state (for workflows), references, etc...
33  * @author Serge Huber
34  */

35 public abstract class ContentObject extends JahiaObject {
36
37     private static org.apache.log4j.Logger logger =
38         org.apache.log4j.Logger.getLogger(ContentObject.class);
39
40
41     public static final String JavaDoc SHARED_LANGUAGE = "shared";
42
43     protected ContentObject(ObjectKey objectKey) {
44         super(objectKey);
45     }
46
47     /**
48      * No arg constructor to support serialization
49      */

50     protected ContentObject() {
51
52     }
53
54     /**
55      * Retrieves all the ContentObjectEntryState for this content object.
56      * @return a SortedSet containing ContentObjectEntryState objects.
57      * @throws JahiaException thrown in case there was a problem retrieving
58      * the entry states
59      */

60     public abstract SortedSet getEntryStates ()
61         throws JahiaException ;
62
63     /**
64      * Retrieves all the active or staging ContentObjectEntryState for this content object.
65      * Should be optimized by subclasses
66      *
67      * @return a SortedSet containing ContentObjectEntryState objects.
68      * @throws JahiaException thrown in case there was a problem retrieving
69      * the entry states
70      */

71     public SortedSet getActiveAndStagingEntryStates()
72         throws JahiaException {
73        SortedSet entries = getEntryStates();
74        SortedSet results = new TreeSet();
75        Iterator iterator = entries.iterator();
76        ContentObjectEntryState entryState = null;
77        while ( iterator.hasNext() ){
78            entryState = (ContentObjectEntryState)iterator.next();
79            if ( entryState.getWorkflowState()
80                 >ContentObjectEntryState.WORKFLOW_STATE_VERSIONED ){
81                results.add(entryState);
82            }
83        }
84        return results;
85     }
86
87     /**
88      * Returns all the childrens of this object, given the current context of
89      * the current user (permissions are checked), the current EntryLoadRequest
90      * (used to determine if we are loading active, staging or versioned
91      * entries), and the current operation mode, to check for invalid state
92      * mixtures (such as loading a versioned entry in active mode !)
93      *
94      * @param user the JahiaUser for whom to retrieve the children objects
95      * @param loadRequest the EntryLoadRequest specifying for which state
96      * to retrive the child objects
97      * @param operationMode the operation mode, this is a value of ParamBean.NORMAL,
98      * ParamBean.EDIT or ParamBean.PREVIEW
99      *
100      * @return an ArrayList of ContentObject objects that are the children of
101      * this object. If the case of a ContentContainer, the children might be
102      * ContentFields and ContentContainerLists !
103      *
104      * @throws JahiaException thrown in case there was a problem retrieving
105      * the children of this object.
106      */

107     public abstract ArrayList getChilds (JahiaUser user,
108                                          EntryLoadRequest loadRequest)
109         throws JahiaException;
110
111     /**
112      * Returns the parent ContentObject if there is one, according to the
113      * context passed in the parameters
114      *
115      * @param user the JahiaUser for whom to retrieve the parent object
116      * @param loadRequest the EntryLoadRequest specifying for which state
117      * to retrive the parent object
118      * @param operationMode the operation mode, this is a value of ParamBean.NORMAL,
119      * ParamBean.EDIT or ParamBean.PREVIEW
120      *
121      * @return a ContentObject that is the parent object of this object.
122      * Returns null if the object has no parent.
123      *
124      * @throws JahiaException thrown if there was an error retrieving the parent
125      * of this object.
126      */

127     public abstract ContentObject getParent(JahiaUser user,
128                                             EntryLoadRequest loadRequest,
129                                             String JavaDoc operationMode)
130         throws JahiaException;
131
132
133     /**
134      * Mark a content object's language for deletion. Does nothing if the
135      * language doesn't exist, but if it exists only in staging, the staging
136      * entry is removed. Make sure you include as many languages as you can
137      * when calling this method instead of calling this method multiple times.
138      * Since we are doing delete of entries in certain cases (such as content
139      * that only exists in staging mode), the content object tree might not be
140      * navigateable once this method has been called. Also this method WILL
141      * implicetely delete sub content if a content object is to be completely
142      * removed by the marking operation
143      *
144      * @param user the user performing the operation, in order to perform
145      * rights checks
146      * @param languageCode the language to mark for deletion. Make sure you
147      * include as many languages as you can when calling this method instead
148      * of calling this method multiple times. Since we are doing delete of
149      * entries in certain cases (such as content that only exists in staging
150      * mode), the content object tree might not be navigateable once this
151      * method has been called.
152      * @param stateModificationContext contains the start object of the
153      * operation, as well as settings such as recursive descending in sub pages,
154      * and content object stack trace.
155      *
156      * @throws JahiaException raised if there was a problem while marking the
157      * content object for deletion (mostly related to communication with the
158      * database)
159      */

160     public abstract void markLanguageForDeletion (JahiaUser user,
161                                                   String JavaDoc languageCode,
162                                                   StateModificationContext
163                                                   stateModificationContext)
164         throws JahiaException;
165
166     /**
167      * This method is called when a entry should be copied into a new entry
168      * it is called when an old version -> active version move occurs
169      * This method should not write/change the DBValue, the service handles that.
170      * @param fromEntryState the entry state that is currently was in the database
171      * @param toEntryState the entry state that will be written to the database
172      */

173     protected abstract void copyEntry (EntryStateable fromEntryState,
174                                        EntryStateable toEntryState)
175         throws JahiaException;
176
177     /**
178      * This method is called when an entry should be deleted for real.
179      * It is called when a object is deleted, and versioning is disabled, or
180      * when staging values are undone.
181      * For a bigtext content fields for instance, this method should delete
182      * the text file corresponding to the field entry
183      * @param deleteEntryState the entry state to delete
184      * @param jParams ParamBean needed to destroy page related data such as
185      * fields, sub pages, as well as generated JahiaEvents.
186      */

187     protected abstract void deleteEntry (EntryStateable deleteEntryState)
188         throws JahiaException;
189
190     /**
191      * This method must be implemented by content objects to specify whether
192      * it can be restored from this entry state. The entry state must be a
193      * versioned entry state or the result will not be predictable.
194      *
195      * This method should be redefined by content objects that need to add their
196      * own checks, calling this method first to make sure the entry states
197      * do exist.
198      *
199      * @param user the JahiaUser performing the request. Can be used for rights
200      * checks, especially if doing checks on child objects.
201      * @param operationMode the operation mode we are working in, used mostly
202      * for accessing child objects.
203      * @param entryState a VERSIONED entry state that contains the version ID
204      * and language for which to restore.
205      * @param removeMoreRecentActive specifies whether content that didn't exist at
206      * the time of the versionID but was created and activated after this
207      * versionID should be kept or remove (ie marked for deletion).
208      * @param stateModificationContext a StateModificationContext class that
209      * contains the start object, the path through which we went, as well
210      * as whether we are descending recursively through sub pages or not.
211      *
212      * @return a RestoreVersionTestResults object that contains the status as
213      * well as messages resulting of the test for restoration of the request
214      * version.
215      *
216      * @throws JahiaException in case there was a problem retrieving the
217      * entry states from the database.
218      */

219     public RestoreVersionTestResults isValidForRestore(JahiaUser user,
220                                      String JavaDoc operationMode,
221                                      ContentObjectEntryState entryState,
222                                      boolean removeMoreRecentActive,
223                                      StateModificationContext stateModificationContext)
224         throws JahiaException {
225         RestoreVersionTestResults opResult = new RestoreVersionTestResults();
226         if (!removeMoreRecentActive) {
227             ContentObjectEntryState resultEntryState =
228                 getClosestVersionedEntryState(entryState);
229             if (resultEntryState == null) {
230                 opResult.setStatus(RestoreVersionTestResults.
231                                    FAILED_OPERATION_STATUS);
232                 opResult.appendError(new RestoreVersionNodeTestResult(
233                     getObjectKey(),
234                     entryState.getLanguageCode(),
235                     "No entry found found for this version"));
236             }
237         }
238         return opResult;
239     }
240
241     /**
242      * Restores a version of this content object. Basically a restore is a
243      * copy operation of a previous version into the staging version, overwriting
244      * the existing staging entry if it exists. If the object did not exist
245      * at the time and has been created (and activated) since then, an option
246      * is used to specify whether it should be kept or removed (ie marked for
247      * deletion).
248      *
249      * @param user the user performing the restore operation, used to do rights
250      * checks
251      * @param operationMode the operation mode used to do the restore, used to
252      * load more or less of the object children depending on the mode. (should
253      * mostly always be EDIT)
254      * @param entryState the entry state containing the version ID and the
255      * language code for which to restore the content object.
256      * @param removeMoreRecentActive specifies whether content that didn't exist at
257      * the time of the versionID but was created and activated after this
258      * versionID should be kept or removed (ie marked for deletion).
259      * @param stateModificationContext the state modification context used to
260      * specify the start object of the restore operation, whether it should
261      * be recursive into the subpages, and a stack trace object that may be
262      * use to do loop detection (currently not implemented).
263      *
264      * @return a RestoreVersionTestResults object that contains the status (failed,
265      * partial or complete) and messages resulting of the restore operation on
266      * the content object tree.
267      *
268      * @throws JahiaException in case there was a problem retrieving content
269      * object data from the database
270      *
271      */

272     public RestoreVersionTestResults restoreVersion (JahiaUser user,
273         String JavaDoc operationMode,
274         ContentObjectEntryState entryState,
275         boolean removeMoreRecentActive,
276         RestoreVersionStateModificationContext stateModificationContext)
277         throws JahiaException {
278
279         RestoreVersionTestResults opResult = new RestoreVersionTestResults();
280         /**
281          * This test has no meaning because some content object could miss in some language
282          * and this case should not abort the restore process
283          *
284         opResult.merge(isValidForRestore(user, operationMode, entryState, removeMoreRecentActive, stateModificationContext));
285         if (opResult.getStatus() == RestoreVersionTestResults.FAILED_OPERATION_STATUS) {
286             return opResult;
287         }*/

288
289         ContentObjectEntryState resultEntryState = getClosestVersionedEntryState(entryState);
290
291         // now let's find the active and staging entries if they exist for this
292
// language code.
293
ContentObjectEntryState stagingEntryState = null;
294         SortedSet allEntryStates = getEntryStates();
295         Iterator entryStatesIter = allEntryStates.iterator();
296         while (entryStatesIter.hasNext()) {
297             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStatesIter.next();
298             if (curEntryState.getWorkflowState() == ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) {
299                 if (curEntryState.getLanguageCode().equals(entryState.getLanguageCode()) ||
300                     ContentObject.SHARED_LANGUAGE.equals(curEntryState.getLanguageCode())) {
301                     
302                 }
303             } else if (curEntryState.getWorkflowState() >= ContentObjectEntryState.WORKFLOW_STATE_START_STAGING) {
304                 if (curEntryState.getLanguageCode().equals(entryState.getLanguageCode()) ||
305                     ContentObject.SHARED_LANGUAGE.equals(curEntryState.getLanguageCode())) {
306                     stagingEntryState = curEntryState;
307                 }
308             }
309         }
310
311         boolean markedForDelete = false;
312         boolean isDeleted = this.isDeletedOrDoesNotExist(entryState.getVersionID());
313         if (removeMoreRecentActive) {
314             // we're not keeping active versions that date after the requested
315
// version, so let's mark it for deletion if it exists.
316
if (isDeleted){
317                 // deleted in all lang
318
markLanguageForDeletion(user, ContentObject.SHARED_LANGUAGE,
319                         stateModificationContext);
320                 markedForDelete = true;
321             } else if ( resultEntryState == null || (resultEntryState != null &&
322                 (resultEntryState.getWorkflowState()
323                 == EntryLoadRequest.DELETED_WORKFLOW_STATE)) ) {
324                 // delete only in requested lang
325
markLanguageForDeletion(user, entryState.getLanguageCode(),
326                         stateModificationContext);
327                 markedForDelete = true;
328            }
329         }
330
331         if ( markedForDelete || resultEntryState == null ) {
332             return opResult;
333         }
334         // if there is a staged version currently, let's remove it first
335
if (stagingEntryState != null) {
336             deleteEntry(stagingEntryState);
337         }
338
339         if ( stagingEntryState == null ||
340              stagingEntryState.getVersionID()
341              == EntryLoadRequest.DELETED_WORKFLOW_STATE ){
342             // mark for deletion, so recreate a new entry
343
stagingEntryState = new ContentObjectEntryState(
344                 ContentObjectEntryState.WORKFLOW_STATE_START_STAGING, 0,
345                 entryState.getLanguageCode());
346         }
347
348         // FIXME : NK
349
// At this point, the resultEntryState could be of SHARED language code
350
// ( case of shared language field, like Page Field ).
351
// This situation actually cause troubles in further DB operations calls.
352
// Typically, with content page field, the copyEntry(...) will apply the
353
// same entry changes to its Content Object ( ContentPage ) with
354
// fromEntryState lang = SHARED while the content page itself is not
355
// SHARED !!!!!!!! , which is a wrong situation.
356
// that is why we take care to have the correct lang code.
357
// This issue was bring out when undeleting page of link types
358
resultEntryState = new ContentObjectEntryState(resultEntryState.getWorkflowState(),
359                     resultEntryState.getVersionID(), entryState.getLanguageCode());
360         // same concern with stagingEntryState
361
stagingEntryState = new ContentObjectEntryState(stagingEntryState.getWorkflowState(),
362             stagingEntryState.getVersionID(),entryState.getLanguageCode());
363
364         // now let's copy from the versioned entry to a staging entry.
365
copyEntry(resultEntryState, stagingEntryState);
366
367         return opResult;
368     }
369
370     /**
371      * Returns an integer representing the identifier of the ContentObject.
372      * This is SPECIFIC to the ContentObject class, so it's not unique for
373      * ALL ContentObjects, just within a specific class.
374      * Note: this uses the underlying ObjectKey class, which uses String for
375      * the IDInType identifier. So this implementation parses the String and
376      * expects a int within. An exception will be raised if no integer is
377      * found.
378      * @todo solve this IDInType (String) to ID (int) conversion problem.
379      * @return an integer representing the identifier of the Object's instance.
380      * within the type
381      */

382     public int getID() {
383         return getObjectKey().getIdInType();
384     }
385
386     /**
387      * Returns the identifier of the Content Definition for this Content object.
388      *
389      * @param loadRequest
390      * @return
391      */

392     public abstract int getDefinitionID(EntryLoadRequest loadRequest);
393
394     /**
395      * Returns the Definition Key of the Content Definition for this Content object.
396      *
397      * @param loadRequest
398      * @return
399      */

400     public abstract ObjectKey getDefinitionKey(EntryLoadRequest loadRequest);
401
402
403     /**
404      * Find and returns the closest versioned entry state for this content
405      * object if it is available. Otherwise returns null.
406      *
407      * @param entryState a VERSIONED entry state (null returned if invalid),
408      * that contains the versionID and language for which to find the entry
409      * state.
410      *
411      * @return a entry state resolved for the object. This can then be used for
412      * operations that need to work with real entry states.
413      *
414      * @throws JahiaException thrown in case there was a problem retrieving
415      * the entry states from the database.
416      */

417     public ContentObjectEntryState getClosestVersionedEntryState(ContentObjectEntryState entryState)
418         throws JahiaException {
419         return getClosestVersionedEntryState(entryState,false);
420     }
421
422     /**
423      * Find and returns the closest versioned entry state for this content
424      * object if it is available. Otherwise returns null.
425      *
426      * @param entryState a VERSIONED entry state (null returned if invalid),
427      * that contains the versionID and language for which to find the entry
428      * state.
429      *
430      * @return a entry state resolved for the object. This can then be used for
431      * operations that need to work with real entry states.
432      *
433      * @throws JahiaException thrown in case there was a problem retrieving
434      * the entry states from the database.
435      */

436     public ContentObjectEntryState getClosestVersionedEntryState(ContentObjectEntryState entryState, boolean smallerVersionOnly)
437         throws JahiaException {
438
439         if (entryState.getWorkflowState() >
440             ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) {
441             logger.debug(
442                 "Invalid workflow state requested when trying to find versioned entry state: " +
443                 entryState.getWorkflowState());
444             return null;
445         }
446         // let's test if we have a version id that exists prior to or equal
447
// to the one we've been asked for in this language.
448
SortedSet entryStates = getEntryStates();
449         ContentObjectEntryState resultEntryState = null;
450         Iterator entryStatesIter = entryStates.iterator();
451
452         while (entryStatesIter.hasNext()) {
453             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStatesIter.next();
454             if (curEntryState.getWorkflowState() <= ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) {
455                 if ( smallerVersionOnly && (curEntryState.getVersionID() < entryState.getVersionID())
456                      || !smallerVersionOnly && (curEntryState.getVersionID() <= entryState.getVersionID()) ){
457                     // we must now still test if the language corresponds.
458
if (curEntryState.getLanguageCode().equals(entryState.getLanguageCode()) ||
459                         curEntryState.getLanguageCode().equals(ContentObject.SHARED_LANGUAGE) ||
460                         ContentObject.SHARED_LANGUAGE.equals(entryState.getLanguageCode())) {
461                         if (resultEntryState != null) {
462                             // now let's test if it's closer to our previous result.
463
if (resultEntryState.getVersionID() < curEntryState.getVersionID()) {
464                                 resultEntryState = curEntryState;
465                             }
466                         } else {
467                             resultEntryState = curEntryState;
468                         }
469                     }
470                 }
471             }
472
473         }
474         return resultEntryState;
475     }
476
477     /**
478      * Should be implemented by subobject for optimization
479      *
480      * Returns true if the content object has active entries.
481      * @return
482      */

483     public boolean hasActiveEntries() throws JahiaException {
484         SortedSet entryStates = getEntryStates();
485         Iterator entryStatesIter = entryStates.iterator();
486         while (entryStatesIter.hasNext()) {
487             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStatesIter.next();
488             if ( curEntryState.getWorkflowState()
489                  ==ContentObjectEntryState.WORKFLOW_STATE_ACTIVE ){
490                 return true;
491             }
492         }
493         return false;
494     }
495
496     /**
497      * Should be implemented by subobject for optimization
498      *
499      * Returns true if the content object has active entries.
500      * @return
501      */

502     public boolean hasActiveOrStagingEntries() throws JahiaException {
503         SortedSet entryStates = getEntryStates();
504         Iterator entryStatesIter = entryStates.iterator();
505         while (entryStatesIter.hasNext()) {
506             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStatesIter.next();
507             if ( curEntryState.getWorkflowState()
508                  >=ContentObjectEntryState.WORKFLOW_STATE_ACTIVE ){
509                 return true;
510             }
511         }
512         return false;
513     }
514
515     /**
516      * Returns true if this Content Object has an archive entryState
517      * before or at a given versionID
518      *
519      * @param VersionID
520      * @return
521      * @throws JahiaException
522      */

523     public boolean hasArchiveEntryState(int versionID) throws JahiaException {
524         return hasArchiveEntryState(versionID,false);
525     }
526
527     /**
528      * Returns true if this Content Object has an archive entryState
529      * before or at a given versionID
530      *
531      * @param versionID int
532      * @param notDeletedOnly boolean, allow deleted entry or not
533      * @throws JahiaException
534      * @return boolean
535      */

536     public boolean hasArchiveEntryState(int versionID,
537                                         boolean notDeletedOnly) throws JahiaException {
538
539         SortedSet entryStates = getEntryStates();
540         Iterator entryStatesIter = entryStates.iterator();
541         while (entryStatesIter.hasNext()) {
542             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStatesIter.next();
543             if ( curEntryState.getWorkflowState()<=ContentObjectEntryState.WORKFLOW_STATE_ACTIVE
544                  && curEntryState.getVersionID()<=versionID ){
545                 if ( !notDeletedOnly ||
546                      (curEntryState.getWorkflowState() != ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED) ){
547                     return true;
548                 }
549             }
550         }
551         return false;
552     }
553
554     /**
555      * Find and returns the closest versioned entry state for the given
556      * version ID, in ALL languages that weren't deleted at the time.
557      *
558      * @param versionID the identifier of the version we want to retrieve
559      * the list of languages that were actually active at the time (deleted
560      * languages are only taken into account if the version ID matches the
561      * entry state version ID).
562      *
563      * @return an ArrayList containing ContentObjectEntryState objects that
564      * are the various language entry states that correspond to the closest
565      * versions for each language.
566      *
567      * @throws JahiaException thrown in case there was a problem retrieving
568      * the entry states from the database.
569      */

570     public ArrayList getClosestVersionedEntryStates(int versionID)
571         throws JahiaException {
572
573
574         // let's test if we have a version id that exists prior to or equal
575
// to the one we've been asked for
576
Map closestInLanguage = new HashMap();
577         SortedSet entryStates = getEntryStates();
578         ContentObjectEntryState resultEntryState = null;
579         Iterator entryStatesIter = entryStates.iterator();
580         while (entryStatesIter.hasNext()) {
581             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStatesIter.next();
582             if ( ((curEntryState.getWorkflowState() == ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) &&
583                   (curEntryState.getVersionID() <= versionID))
584                  ||
585                 ((curEntryState.getWorkflowState() == ContentObjectEntryState.WORKFLOW_STATE_VERSIONED) &&
586                   (curEntryState.getVersionID() <= versionID))
587                  ||
588                  ((curEntryState.getWorkflowState() == ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED) &&
589                   (curEntryState.getVersionID() <= versionID))
590                  ) {
591
592                 // we found an acceptable versioned entry state, let's check
593
// if it's closer in the language.
594
// first we retrieve the current closest version ID for the
595
// language if it exists...
596
resultEntryState = (ContentObjectEntryState) closestInLanguage.get(curEntryState.getLanguageCode());
597                 if (resultEntryState != null) {
598                     // now let's test if it's closer to our previous result.
599
if (resultEntryState.getVersionID() <
600                         curEntryState.getVersionID()) {
601                         closestInLanguage.put(curEntryState.getLanguageCode(), curEntryState);
602                     }
603                 } else {
604                     // no version found for this language, let's add it.
605
closestInLanguage.put(curEntryState.getLanguageCode(), curEntryState);
606                 }
607             }
608
609         }
610         ArrayList resultEntryStates = new ArrayList(closestInLanguage.values());
611         return resultEntryStates;
612     }
613
614     /**
615      * Check if the user has administration access on the specified content object.
616      * Admininistration access means having the ability to add pages, containers
617      * and fields, but also giving rights to users to the different objects/
618      * applications in the specified page.
619      *
620      * @param user Reference to the user.
621      *
622      * @return Return true if the user has read access for the specified object,
623      * or false in any other case.
624      */

625     public final boolean checkAdminAccess(JahiaUser user) {
626         return checkAccess(user, JahiaBaseACL.ADMIN_RIGHTS, false);
627     }
628     
629     public final boolean checkAdminAccess(JahiaUser user,boolean checkChilds) {
630         return checkAccess(user, JahiaBaseACL.ADMIN_RIGHTS,checkChilds);
631     }
632
633     /**
634      * Check if the user has read access on the specified content object. Read
635      * access means having the rights to display and read the content object.
636      *
637      * @param user Reference to the user.
638      *
639      * @return Return true if the user has read access for the specified object,
640      * or false in any other case.
641      */

642     public final boolean checkReadAccess(JahiaUser user) {
643         return checkAccess(user, JahiaBaseACL.READ_RIGHTS, false);
644     }
645
646     /**
647      * Check if the user has write access on the specified content object. Write
648      * access means adding new pages, containers and fields in the specified
649      * content object.
650      *
651      * @param user Reference to the user.
652      *
653      * @return Return true if the user has read access for the specified object,
654      * or false in any other case.
655      */

656     public final boolean checkWriteAccess(JahiaUser user) {
657         return checkAccess(user, JahiaBaseACL.WRITE_RIGHTS, false);
658     }
659     
660     public final boolean checkWriteAccess(JahiaUser user,boolean checkChilds) {
661         return checkAccess(user, JahiaBaseACL.WRITE_RIGHTS,checkChilds);
662     }
663
664     public final boolean checkWriteAccess(JahiaUser user,boolean checkChilds,boolean forceChildsRights) {
665         return checkAccess(user, JahiaBaseACL.WRITE_RIGHTS,checkChilds,forceChildsRights);
666     }
667
668     /**
669      * Check if the user has a specified access to the specified content object.
670      * @param user Reference to the user.
671      * @param permission One of READ_RIGHTS, WRITE_RIGHTS or ADMIN_RIGHTS permission
672      * flag.
673      * @return Return true if the user has the specified access to the specified
674      * object, or false in any other case.
675      */

676     public boolean checkAccess(JahiaUser user, int permission, boolean checkChilds) {
677         boolean result = false;
678         try {
679             JahiaBaseACL acl = new JahiaBaseACL(getAclID());
680             result = acl.getPermission (user, permission);
681             if(!result&& checkChilds) {
682                 List childs = getChilds(user, null);
683                 for (int i = 0; i < childs.size() && !result; i++) {
684                     ContentObject contentObject = (ContentObject) childs.get(i);
685                     if(!(contentObject instanceof ContentPage))
686                         result = contentObject.checkAccess(user, permission,checkChilds);
687                 }
688             }
689         } catch (JahiaException ex) {
690             logger.debug("Cannot load ACL ID " + getAclID(), ex);
691         }
692         return result;
693     }
694     
695     /**
696      * Check if the user has a specified access to the specified content object.
697      * @param user Reference to the user.
698      * @param permission One of READ_RIGHTS, WRITE_RIGHTS or ADMIN_RIGHTS permission
699      * flag.
700      * @return Return true if the user has the specified access to the specified
701      * object, or false in any other case.
702      */

703     public boolean checkAccess(JahiaUser user, int permission, boolean checkChilds,boolean forceChildRights) {
704         boolean result = false;
705         try {
706             JahiaBaseACL acl = getACL();
707             result = acl.getPermission (user, permission);
708             if(result && forceChildRights) {
709                 List childs = getChilds(user, Jahia.getThreadParamBean().getEntryLoadRequest());
710                 for (int i = 0; i < childs.size() && result; i++) {
711                     ContentObject contentObject = (ContentObject) childs.get(i);
712                     result = contentObject.checkAccess(user, permission,checkChilds,forceChildRights);
713                 }
714             }
715         } catch (JahiaException ex) {
716             logger.debug("Cannot load ACL ID " + getAclID(), ex);
717         }
718         return result;
719     }
720
721     /**
722      * This method is used to determine if all the active entries of this
723      * field will be deleted once this object is activated.
724      *
725      * @param markDeletedLanguageCode an extra language to be removed, to add
726      * testing before actually marking for deletion. This may be null in the
727      * case we just want to test the current state.
728      * @param activationLanguageCodes a set of language for which we are
729      * currently activating. May be null if we want to test for all the
730      * languages, but if specified will test if the object will be completly
731      * deleted when activated with only those languages.
732      *
733      * @return true if in the next activation there will be no active entries
734      * left.
735      *
736      * @throws JahiaException in case there was a problem retrieving the
737      * entry states from the database
738      */

739     public boolean willBeCompletelyDeleted(String JavaDoc markDeletedLanguageCode,
740                                            Set activationLanguageCodes)
741         throws JahiaException {
742
743         if (ContentObject.SHARED_LANGUAGE.equals(markDeletedLanguageCode) ){
744             return true;
745         }
746         
747         Set deactivatedLanguageCodes = new HashSet();
748         JahiaSite jahiaSite = ServicesRegistry.getInstance().getJahiaSitesService().getSite(getSiteID());
749         if (jahiaSite != null) {
750             Vector siteLanguageSettings = jahiaSite.getLanguageSettings();
751             Enumeration siteLanguageSettingsEnum = siteLanguageSettings.elements();
752             while (siteLanguageSettingsEnum.hasMoreElements() ) {
753                 SiteLanguageSettings curSettings = (SiteLanguageSettings) siteLanguageSettingsEnum.nextElement();
754                 if (!curSettings.isActivated()) {
755                     deactivatedLanguageCodes.add(curSettings.getCode());
756                 }
757             }
758         }
759
760         SortedSet entryStates = this.getActiveAndStagingEntryStates();
761         Iterator entryStateIter = entryStates.iterator();
762         ArrayList stagedEntryStates = new ArrayList();
763         ArrayList activeEntryStates = new ArrayList();
764         while (entryStateIter.hasNext()) {
765             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStateIter.next();
766             if (curEntryState.isActive()) {
767                 activeEntryStates.add(curEntryState);
768             } else if (curEntryState.isStaging()) {
769                 stagedEntryStates.add(curEntryState);
770             }
771         }
772
773         if ( this.isShared() && markDeletedLanguageCode == null ){
774             if ( activeEntryStates.size()==0 && stagedEntryStates.size()==0){
775                 return true;
776             }
777             if ( stagedEntryStates.size()==0 ){
778                 return false;
779             }
780             ContentObjectEntryState entry =
781                     (ContentObjectEntryState)stagedEntryStates.get(0);
782             return ( entry.getVersionID() ==
783                  ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED );
784         }
785
786         Set languageCodes = new HashSet();
787
788         // first let's get all the active languages into the set.
789
for (int i=0; i<activeEntryStates.size(); i++)
790         {
791             ContentObjectEntryState entryState = (ContentObjectEntryState)activeEntryStates.get(i);
792             languageCodes.add(entryState.getLanguageCode());
793         }
794
795         // now let's remove all the languages that are flagged for deletion.
796
for (int i=0; i<stagedEntryStates.size(); i++)
797         {
798             ContentObjectEntryState entryState = (ContentObjectEntryState)stagedEntryStates.get(i);
799             if (entryState.getVersionID() == -1) {
800                 if (activationLanguageCodes == null ) {
801                     languageCodes.remove(entryState.getLanguageCode());
802                 } else {
803                     // we are only testing for a subset of languages, let's
804
// remove them only if within the subset. We also handle the
805
// case of deactivated language codes here, meaning that deactivated
806
// languages will be included in the removal automatically.
807
if (activationLanguageCodes.contains(entryState.getLanguageCode()) ||
808                         deactivatedLanguageCodes.contains(entryState.getLanguageCode()) ) {
809                         languageCodes.remove(entryState.getLanguageCode());
810                     }
811                 }
812             } else if ( !languageCodes.contains(entryState.getLanguageCode()) ){
813                 // exist only in staging ( not marked for delete ) , not in active
814
languageCodes.add(entryState.getLanguageCode());
815             }
816         }
817
818         // now let's remove the parameter if added.
819
if (markDeletedLanguageCode != null) {
820             languageCodes.remove(markDeletedLanguageCode);
821         }
822
823         if (languageCodes.size() == 0) {
824             return true;
825         } else {
826             return false;
827         }
828     }
829
830     /**
831      * This method is used to determine if all the active entries of this
832      * content's childs will be deleted once this object is activated.
833      *
834      * @param markDeletedLanguageCode an extra language to be removed, to add
835      * testing before actually marking for deletion. This may be null in the
836      * case we just want to test the current state.
837      * @param activationLanguageCodes a set of language for which we are
838      * currently activating. May be null if we want to test for all the
839      * languages, but if specified will test if the object will be completly
840      * deleted when activated with only those languages.
841      *
842      * @return true if in the next activation there will be no active entries
843      * left.
844      *
845      * @throws JahiaException in case there was a problem retrieving the
846      * entry states from the database
847      */

848     public boolean willAllChildsBeCompletelyDeleted(JahiaUser user,
849             String JavaDoc markDeletedLanguageCode, Set activationLanguageCodes)
850         throws JahiaException {
851
852         ArrayList childs = this.getChilds(user,null);
853         int size = childs.size();
854         ContentObject contentObject = null;
855         for ( int i=0 ; i<size; i++ ){
856             contentObject = (ContentObject)childs.get(i);
857             if ( !contentObject.willBeCompletelyDeleted(markDeletedLanguageCode,
858                     activationLanguageCodes) ){
859                 return false;
860             }
861             if ( !contentObject.willAllChildsBeCompletelyDeleted(user,
862                     markDeletedLanguageCode, activationLanguageCodes) ){
863                 return false;
864             }
865         }
866         return true;
867     }
868
869     /**
870      * Returns a set of languages that represents all the languages in active
871      * or staging mode, including or not the languages marked for deletion.
872      * @param includingMarkedForDeletion set this boolean to true if you want
873      * the result to include the languages marked for deletion in staging mode.
874      * @return a Set of String objects that contain the language codes.
875      * @throws JahiaException thrown in case there was a problem loading the
876      * entry states from the database.
877      */

878     public Set getStagingLanguages(boolean includingMarkedForDeletion)
879         throws JahiaException {
880         return getStagingLanguages(true,includingMarkedForDeletion);
881     }
882
883     /**
884      * Returns a set of languages that represents all the languages in active
885      * or staging mode, including or not the languages marked for deletion.
886      * @param includingMarkedForDeletion set this boolean to true if you want
887      * the result to include the languages marked for deletion in staging mode.
888      * @return a Set of String objects that contain the language codes.
889      * @throws JahiaException thrown in case there was a problem loading the
890      * entry states from the database.
891      */

892     public Set getStagingLanguages(boolean withActive,
893                                    boolean includingMarkedForDeletion)
894         throws JahiaException {
895         Set languageCodes = new HashSet();
896         SortedSet entryStates = getEntryStates();
897         Iterator entryStateIter = entryStates.iterator();
898         while (entryStateIter.hasNext()) {
899             ContentObjectEntryState curEntryState = (ContentObjectEntryState) entryStateIter.next();
900             if ( (withActive && curEntryState.isActive()) || curEntryState.isStaging()) {
901                 languageCodes.add(curEntryState.getLanguageCode());
902             }
903         }
904
905         if (!includingMarkedForDeletion) {
906             // now let's remove the languages marked for deletion.
907
Iterator entryStateIter2 = entryStates.iterator();
908             while (entryStateIter2.hasNext()) {
909                 ContentObjectEntryState curEntryState = (
910                     ContentObjectEntryState) entryStateIter2.next();
911                 if (curEntryState.isStaging() &&
912                     (curEntryState.getVersionID() == -1)) {
913                     languageCodes.remove(curEntryState.getLanguageCode());
914                 }
915             }
916         }
917
918         return languageCodes;
919     }
920
921     /**
922      * Resolve to a matching entryState, can be null
923      *
924      *
925      * @param entryState
926      * @param smallerVersionOnly, only if versioned
927      * @param activeOrStaging, when requesting a staging and not exists, return or not the staging
928      * @return
929      * @throws JahiaException
930      */

931     public ContentObjectEntryState getEntryState(ContentObjectEntryState entryState,
932             boolean smallerVersionOnly, boolean activeOrStaging) throws JahiaException {
933         if ( entryState == null ){
934             return null;
935         }
936         if (entryState.getWorkflowState() < ContentObjectEntryState.WORKFLOW_STATE_ACTIVE){
937             return getClosestVersionedEntryState(entryState,smallerVersionOnly);
938         } else {
939             Iterator iterator = this.getActiveAndStagingEntryStates().iterator();
940             ContentObjectEntryState es = null;
941             ContentObjectEntryState activeEntryState = null;
942             ContentObjectEntryState stagingEntryState = null;
943             while ( iterator.hasNext() ){
944                 es = (ContentObjectEntryState)iterator.next();
945                 if ( es.isActive() &&
946                      es.getLanguageCode().equals(entryState.getLanguageCode()) ){
947                     activeEntryState = es;
948                 }
949                 if ( es.isStaging() &&
950                      es.getLanguageCode().equals(entryState.getLanguageCode()) ){
951                     stagingEntryState = es;
952                 }
953             }
954             if ( entryState.isActive() && activeEntryState != null ){
955                 return activeEntryState;
956             }
957             if ( entryState.isStaging() && stagingEntryState != null ){
958                 return stagingEntryState;
959             }
960             if ( entryState.isStaging() && activeOrStaging ){
961                 return activeEntryState;
962             }
963         }
964         return null;
965     }
966
967     /**
968      * Returns the versionID at which the content was the last time deleted.
969      *
970      * @return -1 if the content is not actually deleted otherwise the versionID of the
971      * last delete operation.
972      * @throws JahiaException
973      */

974     public int getDeleteVersionID() throws JahiaException {
975         int versionID = -1;
976         SortedSet entryStates = this.getEntryStates();
977         Iterator iterator = entryStates.iterator();
978         ContentObjectEntryState curEntryState = null;
979         ContentObjectEntryState resultEntryState = null;
980         while ( iterator.hasNext() ){
981             curEntryState = (ContentObjectEntryState)iterator.next();
982             if ( curEntryState.getWorkflowState()
983                  == ContentObjectEntryState.WORKFLOW_STATE_ACTIVE ){
984                 return -1;
985             }
986             if ( curEntryState.getWorkflowState()
987                  == ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED ){
988
989                 if ( resultEntryState == null ){
990                     resultEntryState = curEntryState;
991                 } else {
992                     if ( resultEntryState.getVersionID() < curEntryState.getVersionID() ){
993                         resultEntryState = curEntryState;
994                     }
995                 }
996             }
997         }
998         if ( resultEntryState != null ){
999             versionID = resultEntryState.getVersionID();
1000        }
1001        return versionID;
1002    }
1003
1004    /**
1005     * Return true if the content object is deleted in all language at a given
1006     * date or doesn't exist
1007     *
1008     * @param versionID
1009     * @return
1010     */

1011    public boolean isDeletedOrDoesNotExist(int versionID) throws JahiaException{
1012
1013        ArrayList entryStates =
1014                this.getClosestVersionedEntryStates(versionID);
1015
1016        return isDeletedOrDoesNotExist(entryStates);
1017    }
1018
1019    /**
1020     * Return true if the object is deleted in all language for the given entrystates
1021     *
1022     * @return
1023     */

1024    public boolean isDeletedOrDoesNotExist(Collection entryStates) throws JahiaException{
1025        ContentObjectEntryState entryState = null;
1026        for ( Iterator it = entryStates.iterator() ; it.hasNext(); ){
1027            entryState = (ContentObjectEntryState)it.next();
1028            if ( entryState.getWorkflowState() !=
1029                 ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED ){
1030                return false;
1031            }
1032        }
1033        return true;
1034    }
1035    
1036    /**
1037     * Return true if the content object is deleted in all language at a given
1038     * date.
1039     * @param versionID
1040     * @return
1041     */

1042    public boolean isDeleted(int versionID) throws JahiaException{
1043        ArrayList entryStates =
1044                this.getClosestVersionedEntryStates(versionID);
1045        return isDeleted(entryStates);
1046    }
1047
1048    /**
1049     * Return true if the content object is deleted in all language
1050     * for the given entrystates
1051     * @return
1052     */

1053    public boolean isDeleted(Collection entryStates) throws JahiaException{
1054        int size = entryStates.size();
1055        if (size == 0) {
1056            return false;
1057        }
1058        ContentObjectEntryState entryState = null;
1059        for ( Iterator it = entryStates.iterator() ; it.hasNext(); ){
1060            entryState = (ContentObjectEntryState)it.next();
1061            if ( entryState.getWorkflowState() !=
1062                 ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED ){
1063                return false;
1064            }
1065        }
1066        return true;
1067    }
1068    
1069    /**
1070     * Return true if the current content object is marked for delete
1071     * in all languages
1072     * @return
1073     */

1074    public boolean isMarkedForDelete() throws JahiaException{
1075        Set entryStates = getActiveAndStagingEntryStates();
1076        if ( entryStates.isEmpty() ){
1077            return false;
1078        }
1079        HashMap states = new HashMap();
1080        Iterator iterator = entryStates.iterator();
1081        Boolean JavaDoc bool = null;
1082        while ( iterator.hasNext() ){
1083            ContentObjectEntryState entryState =
1084                (ContentObjectEntryState)iterator.next();
1085            bool = (Boolean JavaDoc)states.get(entryState.getLanguageCode());
1086            if ( bool == null || !bool.booleanValue() ){
1087                if (entryState.getVersionID() !=
1088                    EntryLoadRequest.DELETED_WORKFLOW_STATE) {
1089                    states.put(entryState.getLanguageCode(), Boolean.FALSE);
1090                } else {
1091                    states.put(entryState.getLanguageCode(), Boolean.TRUE);
1092                }
1093            }
1094        }
1095
1096        iterator = states.values().iterator();
1097        while ( iterator.hasNext() ){
1098            bool = (Boolean JavaDoc)iterator.next();
1099            if ( !bool.booleanValue() ){
1100                return false;
1101            }
1102        }
1103        return true;
1104    }
1105
1106    /**
1107     * Return true if the current content object is marked for delete for the given languageCode
1108     *
1109     * @return
1110     */

1111    public boolean isMarkedForDelete(String JavaDoc languageCode) throws JahiaException {
1112        if ( languageCode == null ){
1113            return false;
1114        }
1115
1116        Set entryStates = getActiveAndStagingEntryStates();
1117        ContentObjectEntryState entryState = null;
1118        Iterator iterator = entryStates.iterator();
1119
1120        while (iterator.hasNext()) {
1121            entryState = (ContentObjectEntryState) iterator.next();
1122            if (entryState.isStaging() && (this.isShared()
1123                      || languageCode.equals(entryState.getLanguageCode()))
1124                    && entryState.getVersionID() ==
1125                        EntryLoadRequest.DELETED_WORKFLOW_STATE) {
1126                        return true;
1127            }
1128        }
1129        return false;
1130    }
1131
1132
1133    /**
1134     * This method removes all the data related to the staging mode of this
1135     * object, effectively "undoing" all the changes and returning to the
1136     * active values.
1137     * @throws JahiaException in the case there are errors accessing the
1138     * persistant storage system.
1139     */

1140    public abstract void undoStaging(ParamBean jParams)
1141    throws JahiaException;
1142
1143    /**
1144     * Is this kind of object shared (i.e. not one version for each language, but one version for every language)
1145     */

1146    public abstract boolean isShared ();
1147
1148    /**
1149     * Returns the corresponding ACL id for a content object. This is currently
1150     * an abstract method because the persistence model is different for each
1151     * content object implementation, but this might change in the future.
1152     *
1153     * @return an integer corresponding to the ACL ID of the content object.
1154     */

1155    public abstract int getAclID();
1156
1157    public JahiaBaseACL getACL() throws ACLNotFoundException, JahiaException {
1158        return new JahiaBaseACL(getAclID());
1159    }
1160
1161    /**
1162     * Must be called by Subclasses activate method.
1163     *
1164     * @param languageCodes Set
1165     * @param versioningActive boolean
1166     * @param saveVersion JahiaSaveVersion
1167     * @param jParams ParamBean
1168     * @param stateModifContext StateModificationContext
1169     * @throws JahiaException
1170     */

1171    public void fireContentActivationEvent (Set languageCodes,
1172                                            boolean versioningActive,
1173                                            JahiaSaveVersion saveVersion,
1174                                            ParamBean jParams,
1175                                            StateModificationContext stateModifContext,
1176                                            ActivationTestResults result)
1177    throws JahiaException {
1178
1179            ContentActivationEvent event = new ContentActivationEvent(this,this.getObjectKey(),
1180                jParams.getUser(),languageCodes,versioningActive,saveVersion,jParams,stateModifContext,result);
1181
1182            ServicesRegistry.getInstance().getJahiaEventService()
1183                .fireContentActivation(event);
1184
1185    }
1186
1187    /**
1188     * Return the site ID in which the object is located.
1189     *
1190     * @return Return the page site ID.
1191     */

1192    public abstract int getSiteID();
1193
1194}
1195
Popular Tags