KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > services > pages > ContentPage


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  *
14  * ----- BEGIN LICENSE BLOCK -----
15  * Version: JCSL 1.0
16  *
17  * The contents of this file are subject to the Jahia Community Source License
18  * 1.0 or later (the "License"); you may not use this file except in633
19
20  * compliance with the License. You may obtain a copy of the License at
21  * http://www.jahia.org/license
22  *
23  * Software distributed under the License is distributed on an "AS IS" basis,
24  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
25  * for the rights, obligations and limitations governing use of the contents
26  * of the file. The Original and Upgraded Code is the Jahia CMS and Portal
27  * Server. The developer of the Original and Upgraded Code is JAHIA Ltd. JAHIA
28  * Ltd. owns the copyrights in the portions it created. All Rights Reserved.
29  *
30  * The Shared Modifications are Jahia View Helper.
31  *
32  * The Developer of the Shared Modifications is Jahia Solution S�rl.
33  * Portions created by the Initial Developer are Copyright (C) 2002 by the
34  * Initial Developer. All Rights Reserved.
35  *
36  * Contributor(s):
37  * 13-AUG-2003, Jahia Solutions Sarl, Fulco Houkes
38  *
39  * ----- END LICENSE BLOCK -----
40  */

41
42 package org.jahia.services.pages;
43
44
45 import org.apache.log4j.Logger;
46 import org.jahia.bin.Jahia;
47 import org.jahia.content.*;
48 import org.jahia.data.containers.JahiaContainer;
49 import org.jahia.data.events.JahiaEvent;
50 import org.jahia.data.fields.LoadFlags;
51 import org.jahia.engines.EngineMessage;
52 import org.jahia.exceptions.JahiaException;
53 import org.jahia.exceptions.JahiaPageNotFoundException;
54 import org.jahia.exceptions.JahiaTemplateNotFoundException;
55 import org.jahia.params.ParamBean;
56 import org.jahia.registries.ServicesRegistry;
57 import org.jahia.services.acl.ACLResourceInterface;
58 import org.jahia.services.acl.JahiaACLException;
59 import org.jahia.services.acl.JahiaBaseACL;
60 import org.jahia.services.cache.CacheFactory;
61 import org.jahia.services.cache.HtmlCache;
62 import org.jahia.services.containers.ContentContainer;
63 import org.jahia.services.containers.ContentContainerList;
64 import org.jahia.services.fields.ContentField;
65 import org.jahia.services.fields.ContentPageField;
66 import org.jahia.services.sites.JahiaSite;
67 import org.jahia.services.sites.SiteLanguageSettings;
68 import org.jahia.services.usermanager.JahiaUser;
69 import org.jahia.services.usermanager.JahiaUserManagerService;
70 import org.jahia.services.version.*;
71 import org.jahia.utils.JahiaTools;
72 import org.jahia.utils.LanguageCodeConverters;
73 import org.jahia.utils.xml.XMLSerializationOptions;
74 import org.jahia.utils.xml.XmlWriter;
75
76 import java.io.IOException JavaDoc;
77 import java.io.Serializable JavaDoc;
78 import java.util.*;
79
80 /**
81  * <p>Title: ContentPage - all the content for a page</p>
82  * <p>Description: This class contains all the content in multiple languages
83  * and multiple active versions for a given page. For a single language version
84  * this is represented by JahiaPage.</p>
85  * <p>Copyright: Copyright (c) 2002</p>
86  * <p>Company: </p>
87  *
88  * @author Serge Huber
89  * @version 1.0
90  * @todo FIXME no support for old version restoring exists in this class as
91  * of yet.
92  */

93 public class ContentPage extends ContentObject implements
94         PageInfoInterface, ACLResourceInterface, Comparator, Serializable JavaDoc {
95
96     private static Logger logger = Logger.getLogger (ContentPage.class);
97
98     private Set mPageInfos;
99     private Map mActivePageInfos;
100     private Map mStagingPageInfos;
101     private Set mArchivedPageInfos;
102     private JahiaBaseACL mACL;
103
104     /** Flag used to restore or not page's content ( fields, containers,...) **/
105     private boolean mRestoreContent = true;
106
107     static {
108         JahiaObject.registerType (ContentPageKey.PAGE_TYPE,
109                 ContentPage.class.getName ());
110     }
111
112     public static ContentObject getChildInstance (String JavaDoc IDInType) {
113         try {
114             return getPage (Integer.parseInt (IDInType));
115         } catch (JahiaException je) {
116             logger.debug ("Error retrieving page instance for id : " + IDInType, je);
117         }
118         return null;
119     }
120
121     //-------------------------------------------------------------------------
122
/**
123      * ContentPage constructor. This method is responsible for building
124      * all the internal structure for the multilanguage and multiple staging
125      * /active version data.
126      *
127      * @param pageInfoVector a Vector of JahiaPageInfo object, that contain
128      * all the database entries for the current page
129      * @param pageTemplate the JahiaPageDefinition object containing the
130      * definition for the page
131      * @param acl the JahiaBaseAcl object related to this page
132      *
133      * @throws JahiaException thrown if there were errors while accessing
134      * Jahia services (page and lock)
135      */

136     protected ContentPage (int pageID,
137                            Vector pageInfoVector,
138                            JahiaBaseACL acl)
139             throws JahiaException {
140         super (new ContentPageKey (pageID));
141
142         if (pageInfoVector == null) {
143             throw new JahiaException ("JahiaPage.constructor",
144                     "Database object for page is inexistant ?",
145                     JahiaException.PAGE_ERROR,
146                     JahiaException.CRITICAL_SEVERITY);
147
148         }
149         buildInternalMaps (pageInfoVector);
150
151         mACL = acl;
152
153     }
154
155     /**
156      * No arg constructor to properly support de-serialization
157      */

158     protected ContentPage() {
159     }
160
161     private void buildInternalMaps (Vector pageInfoVector) {
162         int pageInfoCount = pageInfoVector.size();
163         mPageInfos = new HashSet (pageInfoVector);
164         mActivePageInfos = new HashMap ();
165         mStagingPageInfos = new HashMap ();
166         mArchivedPageInfos = new HashSet ();
167         // small code to copy the vector, not the vector elements.
168
for (int i=0; i < pageInfoCount; i++) {
169             JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoVector.get(i);
170             mPageInfos.add (curPageInfo);
171             if (curPageInfo.getWorkflowState () == EntryLoadRequest.ACTIVE_WORKFLOW_STATE) {
172                 mActivePageInfos.put (curPageInfo.getLanguageCode (), curPageInfo);
173             } else {
174                 if (curPageInfo.getWorkflowState () >= EntryLoadRequest.STAGING_WORKFLOW_STATE) {
175                     mStagingPageInfos.put (curPageInfo.getLanguageCode (), curPageInfo);
176                 } else if (curPageInfo.getWorkflowState () <= 0) {
177                     mArchivedPageInfos.add (curPageInfo);
178                 }
179             }
180         }
181     }
182
183     private void rebuildStatusMaps () {
184         mActivePageInfos = new HashMap ();
185         mStagingPageInfos = new HashMap ();
186         mArchivedPageInfos = new HashSet ();
187         // small code to copy the vector, not the vector elements.
188
Iterator pageInfoEnum = mPageInfos.iterator ();
189         while (pageInfoEnum.hasNext ()) {
190             JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoEnum.next ();
191             if (curPageInfo.getWorkflowState () == EntryLoadRequest.ACTIVE_WORKFLOW_STATE) {
192                 mActivePageInfos.put (curPageInfo.getLanguageCode (), curPageInfo);
193             } else {
194                 if (curPageInfo.getWorkflowState () >= EntryLoadRequest.STAGING_WORKFLOW_STATE) {
195                     mStagingPageInfos.put (curPageInfo.getLanguageCode (), curPageInfo);
196                 } else if (curPageInfo.getWorkflowState () <= 0) {
197                     mArchivedPageInfos.add (curPageInfo);
198                 }
199             }
200         }
201     }
202
203     //-------------------------------------------------------------------------
204
/**
205      * Check if the Guest user of a site has read access.
206      *
207      * @param siteID the site id.
208      *
209      * @return Return true if the site's guest user has read access for this page,
210      * or false in any other case.
211      */

212     public final boolean checkGuestAccess (int siteID) {
213         // get the User Manager service instance.
214
JahiaUserManagerService userMgr = ServicesRegistry.getInstance ().
215                 getJahiaUserManagerService ();
216         if (userMgr == null)
217             return false;
218
219         JahiaUser theUser = userMgr.lookupUser (siteID, JahiaUserManagerService.GUEST_USERNAME);
220         if (theUser == null)
221             return false;
222
223         return checkAccess (theUser, JahiaBaseACL.READ_RIGHTS, false);
224     }
225
226
227     //-------------------------------------------------------------------------
228
/**
229      * Flush all the HTML caches corresponding to this page update (useful for
230      * example when we have modified a page title that will be display on
231      * multiple other pages).
232      *
233      * @throws JahiaException raised if there were problems either updating
234      * the persistant data or flushing the cache.
235      */

236     public void invalidateHtmlCache() throws JahiaException {
237
238         // We need to check if there is still some page infos.
239
// it could be empty when called this method after deleting a page
240
// that exists only in staging
241
if (mPageInfos.size() > 0) {
242             // let's flush the cache of all the pages referencing this one.
243
int siteID = getJahiaID();
244             JahiaSite site = ServicesRegistry.getInstance().getJahiaSitesService().getSite(siteID);
245             if (site == null) {
246                 logger.debug("Invalid site for page, cannot flush cache.");
247             } else {
248                 Set pageIds = ContentPageXRefManager.getInstance().getPageIDs(getID());
249                 pageIds.add(new Integer JavaDoc(getID()));
250                 invalidateHtmlCache(pageIds);
251             }
252         }
253     }
254     
255     /**
256      * Flush the HTML caches of the passed page-IDs.
257      *
258      * @param pageIds a Set of page-Ids (Integer)
259      *
260      * @throws JahiaException raised if there were problems either updating
261      * the persistant data or flushing the cache.
262      */

263     public void invalidateHtmlCache(Set pageIds) throws JahiaException {
264
265         Iterator refPagesIter = pageIds.iterator();
266
267         // Get the cache instance and invalidate the related page
268
// entries
269
HtmlCache htmlCache = CacheFactory.getHtmlCache();
270         if (htmlCache == null)
271             logger.warn("Could not get the HTML cache instance!!");
272
273         while (refPagesIter.hasNext()) {
274             Integer JavaDoc curPageID = (Integer JavaDoc) refPagesIter.next();
275
276             if (htmlCache != null)
277                 htmlCache.invalidatePageEntries(curPageID.toString());
278         }
279     }
280     // -------------------------------------------------------------------------
281
/**
282      * Commit the changes made in the page object to the database.
283      *
284      * @param flushCaches
285      * specifies whether we should flush all the caches corresponding
286      * to this page update (useful for example when we have modified
287      * a page title that will be display on multiple other pages).
288      * @param jParams
289      * ParamBean object used to resolve the version and the language
290      * for which to perform all the operations in this method.
291      *
292      * @throws JahiaException
293      * raised if there were problems either updating the persistant
294      * data or flushing the cache.
295      * @todo this is called even for a page counter update, can we avoid that in
296      * the future ?
297      */

298     public synchronized void commitChanges (boolean flushCaches)
299             throws JahiaException {
300         logger.debug ("commitChanges called.");
301         
302         if (flushCaches) {
303             invalidateHtmlCache();
304         }
305
306         Iterator pageInfoIter = mPageInfos.iterator ();
307         while (pageInfoIter.hasNext ()) {
308             JahiaPageInfo curInfo = (JahiaPageInfo) pageInfoIter.next ();
309             curInfo.commitChanges ();
310         }
311
312         ServicesRegistry.getInstance().getJahiaPageService()
313             .invalidatePageCache(getID());
314     }
315
316     /**
317      * @param flushCaches
318      * @param jParams
319      *
320      * @throws JahiaException
321      */

322     public void commitChanges (boolean flushCaches, ParamBean jParams)
323             throws JahiaException {
324         if (jParams != null) {
325             commitChanges (flushCaches);
326         } else {
327             logger.debug ("FIXME : Method called with null ParamBean, not executing...");
328             return;
329         }
330     }
331
332     //-------------------------------------------------------------------------
333
/**
334      * Return the page's ACL object.
335      *
336      * @return Return the page's ACL.
337      */

338     public final JahiaBaseACL getACL () {
339         return mACL;
340     }
341
342
343     //-------------------------------------------------------------------------
344
/**
345      * Return the ACL unique identification number.
346      *
347      * @return Return the ACL ID.
348      */

349     public final int getAclID () {
350         int id = -1;
351         try {
352             id = mACL.getID ();
353         } catch (JahiaACLException ex) {
354             // This exception should not happen ... :)
355
}
356         return id;
357     }
358
359     /**
360      * Get the ACL id corresponding to the page workflow state. The ACL can
361      * change between workflow state due to a page move or a type change. In
362      * the case we get the ACL id from an ARCHIVED_PAGE_INFOS then the last
363      * DIRECT page ACL is returned.
364      *
365      * @param pageInfosFlag Kind of page infos desired. This parameter can be
366      * one of the constants ACTIVE_PAGE_INFOS, STAGING_PAGE_INFOS or
367      * ARCHIVED_PAGE_INFOS.
368      *
369      * @return The ACL id corresponding to the page workflow state.
370      */

371     public final int getAclID (int pageInfosFlag) {
372         if ((pageInfosFlag & 0x01) != 0) {
373             if (this.mActivePageInfos.isEmpty ()) {
374                 return -1;
375             }
376             JahiaPageInfo activePageInfo = (JahiaPageInfo) this.mActivePageInfos.
377                     get (this.mActivePageInfos.keySet ().iterator ().next ());
378             return activePageInfo.getAclID ();
379         } else if ((pageInfosFlag & 0x02) != 0) {
380             if (this.mStagingPageInfos.isEmpty ()) {
381                 return -1;
382             }
383             JahiaPageInfo stagingPageInfo = (JahiaPageInfo) this.mStagingPageInfos.
384                     get (this.mStagingPageInfos.keySet ().iterator ().next ());
385             return stagingPageInfo.getAclID ();
386         } else if ((pageInfosFlag & 0x04) != 0) {
387             // ensure to load versioning entries
388
try {
389                 loadVersioningEntryStates ();
390             } catch (Throwable JavaDoc t) {
391                 logger.debug ("Exception occured loading versioning entries", t);
392             }
393             if (this.mArchivedPageInfos.isEmpty ()) {
394                 return -1;
395             }
396             Iterator it = mArchivedPageInfos.iterator ();
397             int lastVersion = 0;
398             int lastACL = -1;
399             while (it.hasNext ()) {
400                 JahiaPageInfo archivedPageInfo =
401                         (JahiaPageInfo) it.next ();
402                 int versionID = archivedPageInfo.getVersionID ();
403                 if (versionID > lastVersion &&
404                         archivedPageInfo.getPageType () == ContentPage.TYPE_DIRECT) {
405                     lastVersion = versionID;
406                     lastACL = archivedPageInfo.getAclID ();
407                 }
408             }
409             return lastACL;
410         }
411         return -1;
412     }
413
414
415     //-------------------------------------------------------------------------
416
/**
417      * Return the page's hit counter.
418      *
419      * @param jParams ParamBean object used to resolve the version and the
420      * language for which to perform all the operations in this method.
421      *
422      * @return Return the page counter.
423      */

424     public final int getCounter (EntryLoadRequest loadRequest) {
425         int counter = -1;
426         try {
427             counter = Integer.parseInt (getProperty ("counter", loadRequest));
428         } catch (Throwable JavaDoc t) {
429             counter = -1;
430         }
431         return counter;
432     }
433
434     /**
435      * @param jParams
436      *
437      * @return
438      */

439     public final int getCounter (ParamBean jParams) {
440         if (jParams != null) {
441             return getCounter (jParams.getEntryLoadRequest ());
442         } else {
443             logger.debug ("FIXME : Method called with null ParamBean, returning -1");
444             return -1;
445         }
446     }
447
448
449     //-------------------------------------------------------------------------
450
/**
451      * Return the user nickname who created the page. This nickname is the
452      * user name used internally by Jahia.
453      *
454      * @return Return the creator nickname.
455      */

456     public final String JavaDoc getCreator () {
457         return getPageInfoVersion (null, false, true).getCreator ();
458     }
459
460
461     //-------------------------------------------------------------------------
462
/**
463      * Return the page's date of creation in ms from 1975.
464      *
465      * @return Return the date of creation.
466      */

467     public final String JavaDoc getDoc () {
468         return getPageInfoVersion (null, false, true).getDoc ();
469     }
470
471
472     //-------------------------------------------------------------------------
473
/**
474      * Return the site ID in which the page is located.
475      *
476      * @return Return the page site ID.
477      */

478     public final int getJahiaID () {
479         return getPageInfoVersion (null, false, true).getJahiaID ();
480     }
481
482     public final int getSiteID() {
483         return getJahiaID();
484     }
485
486     //-------------------------------------------------------------------------
487
/**
488      * Returns the page definition (also known as template) for the current
489      * ParamBean. (We ignore the language since templates are shared among
490      * languages)
491      *
492      * @param jParams the ParamBean containing the entry load request object
493      * that will allows us to know which entry state to load for.
494      *
495      * @return a page definition according to the entry state we were trying
496      * to load.
497      */

498     public final JahiaPageDefinition getPageTemplate (EntryLoadRequest loadRequest) {
499         int pageDefID = getPageTemplateID (loadRequest);
500         if (pageDefID == -1) {
501             return null;
502         }
503         JahiaPageDefinition pageDef = null;
504         try {
505             pageDef =
506                     ServicesRegistry.getInstance ().getJahiaPageTemplateService ().
507                     lookupPageTemplate (pageDefID);
508         } catch (JahiaException je) {
509             if (this.getPageType (loadRequest) != JahiaPage.TYPE_URL) {
510                 logger.debug ("Error while loading page template : ", je);
511             }
512             return null;
513         }
514         return pageDef;
515     }
516
517     public final JahiaPageDefinition getPageTemplate (ParamBean jParams) {
518         if (jParams != null) {
519             return getPageTemplate (jParams.getEntryLoadRequest ());
520         } else {
521             logger.debug ("FIXME : Method called with null ParamBean, returning null");
522             return null;
523         }
524     }
525     //-------------------------------------------------------------------------
526
/**
527      * Return the page definition ID.
528      *
529      * @param jParams a ParamBean object to be able to specify for which
530      * version/language to retrieve the value of this method.
531      *
532      * @return Return the page definition ID.
533      */

534     public final int getPageTemplateID (ParamBean jParams) {
535         if (jParams != null) {
536             return getPageTemplateID (jParams.getEntryLoadRequest ());
537         } else {
538             logger.debug ("FIXME : calling this method without parambean, returning -1");
539             return -1;
540         }
541     }
542
543     public final int getPageTemplateID (EntryLoadRequest loadRequest) {
544         JahiaPageInfo pageInfo = getPageInfoVersionIgnoreLanguage (loadRequest, false);
545         if (pageInfo == null) {
546             return -1;
547         }
548         return pageInfo.getPageTemplateID ();
549     }
550
551     /**
552      * Returns the identifier of the Content Definition for Content object.
553      * For page, the definition is the Template Page
554      *
555      * @param loadRequest
556      *
557      * @return
558      */

559     public int getDefinitionID (EntryLoadRequest loadRequest) {
560         return this.getPageTemplateID (loadRequest);
561     }
562
563     /**
564      * Returns the Definition Key of the Content Definition for this Content object.
565      * This is a PageDefinitionKey
566      *
567      * @param loadRequest
568      *
569      * @return
570      */

571     public ObjectKey getDefinitionKey (EntryLoadRequest loadRequest) {
572         int defID = getDefinitionID (loadRequest);
573         PageDefinitionKey pageDefKey = (PageDefinitionKey)
574                 PageDefinitionKey.getChildInstance (String.valueOf (defID));
575         return pageDefKey;
576     }
577
578     /**
579      * //-------------------------------------------------------------------------
580      * /**
581      * Return the internal representation of the page information.
582      *
583      * @param withVersioned if true it specifies whether we should retrieve
584      * all the page info entries including the versioned ones, if false it means
585      * we only return the active and staged entries
586      *
587      * @return Return the JahiaPageInfo object.
588      */

589     protected final Vector getPageInfos (boolean withVersioned) {
590         Vector result = new Vector ();
591         result.addAll (mPageInfos);
592
593         if (withVersioned) {
594             Vector versionedPageInfos = null;
595             try {
596                 versionedPageInfos =
597                         JahiaPagesDB.getInstance ().loadPageInfos (getID (),
598                                 EntryLoadRequest.VERSIONED);
599             } catch (JahiaException je) {
600                 logger.debug ("withVersioned=" + withVersioned, je);
601                 versionedPageInfos = new Vector ();
602             }
603             result.addAll (versionedPageInfos);
604         }
605         return result;
606     }
607
608
609     //-------------------------------------------------------------------------
610
/**
611      * Return the internal jahia page ID in case the page is an internal
612      * jahia link.
613      *
614      * @param jParams a ParamBean object to be able to specify for which
615      * version/language to retrieve the value of this method.
616      *
617      * @return Return the page link ID.
618      */

619     public final int getPageLinkID (EntryLoadRequest loadRequest) {
620         JahiaPageInfo pageInfo = getPageInfoVersionIgnoreLanguage (loadRequest, false);
621         if (pageInfo == null) {
622             return -1;
623         }
624         return pageInfo.getPageLinkID ();
625     }
626
627     /**
628      * @param jParams
629      *
630      * @return
631      */

632     public final int getPageLinkID (ParamBean jParams) {
633         if (jParams != null) {
634             return getPageLinkID (jParams.getEntryLoadRequest ());
635         } else {
636             logger.debug ("FIXME : Method called with null ParamBean, returning -1");
637             return -1;
638         }
639     }
640
641     public static ContentPage getPage (int pageID, boolean withTemplate, boolean forceLoadFromDB)
642             throws JahiaException {
643         return ServicesRegistry.getInstance ().getJahiaPageService ().lookupContentPage (
644                 pageID, withTemplate, forceLoadFromDB);
645     }
646     
647     public static ContentPage getPage (int pageID, boolean withTemplate)
648             throws JahiaException {
649         return ServicesRegistry.getInstance ().getJahiaPageService ().lookupContentPage (
650                 pageID, withTemplate, false);
651     }
652
653     public static ContentPage getPage (int pageID)
654             throws JahiaException {
655         return ServicesRegistry.getInstance ().getJahiaPageService ().lookupContentPage (
656                 pageID, true, false);
657     }
658
659     /**
660      * Returns a JahiaPage view object for the specified ParamBean (associated
661      * with the current view mode, the state (moved or not), the current
662      * language, etc...
663      *
664      * @param jParams used to retrieve the current user, the current operation
665      * mode, the current language, etc..
666      *
667      * @return a JahiaPage object corresponding to the current ParamBean object,
668      * or null if the page is not available in this context (operation mode,
669      * ACLs, etc..)
670      *
671      * @throws JahiaException if there was an error accessing the template
672      * registry or the locks registry.
673      */

674     public JahiaPage getPage (EntryLoadRequest loadRequest, String JavaDoc operationMode,
675                               JahiaUser user)
676             throws JahiaException {
677
678         JahiaPage page = new JahiaPage (this,
679                 this.getPageTemplate (loadRequest),
680                 this.getACL (),
681                 loadRequest);
682         if ((loadRequest != null) && (user != null) && (operationMode != null)) {
683             if (!page.checkReadAccess (user)) {
684                 return null;
685             }
686             if (!operationMode.equals (ParamBean.EDIT) && !operationMode.equals (ParamBean.COMPARE)) {
687                 // only allow null titles if in edit mode
688
if (page.getTitle () == null) {
689                     return null;
690                 }
691             }
692             if (!operationMode.equals (ParamBean.NORMAL)
693                     && !operationMode.equals (ParamBean.COMPARE)) {
694                 // only return page in edit or preview mode if we have write
695
// access to it.
696
if (!page.checkWriteAccess (user)) {
697                     // instead let's try to get the page in ACTIVE mode.
698
if (page.checkReadAccess (user)) {
699                         // let's check if the page has active entries first.
700

701                         // NK : EDIT_MODE_PAGE_ACCESS_ISSUE
702
// Edit Mode allowed even the user has no write access on page
703
/*
704                         if (!this.hasActiveEntries()) {
705                             return null;
706                         }*/

707
708                         EntryLoadRequest activeLoadRequest = new EntryLoadRequest (
709                                 EntryLoadRequest.ACTIVE_WORKFLOW_STATE, 0,
710                                 loadRequest.getLocales ());
711                         if (this.getTitle (activeLoadRequest) == null) {
712                             return null;
713                         }
714                         page =
715                                 new JahiaPage (this, this.getPageTemplate (activeLoadRequest),
716                                         this.getACL (), activeLoadRequest);
717                     }
718                 }
719             }
720         } else {
721             logger.debug (
722                     "No ParamBean passed, assuming normal mode and using site guest user to check for read access");
723             if (!this.checkGuestAccess (getJahiaID ())) {
724                 return null;
725             }
726         }
727         return page;
728     }
729
730     /**
731      * @param jParams
732      *
733      * @return
734      *
735      * @throws JahiaException
736      */

737     public JahiaPage getPage (ParamBean jParams)
738             throws JahiaException {
739         if (jParams != null) {
740             return getPage (jParams.getEntryLoadRequest (),
741                     jParams.getOperationMode (), jParams.getUser ());
742         } else {
743             return null;
744         }
745     }
746
747
748     //-------------------------------------------------------------------------
749
/**
750      * Return the page type
751      *
752      * @param jParams a ParamBean object to be able to specify for which
753      * version/language to retrieve the value of this method.
754      *
755      * @return Return the page type, -1 if pageinfo doesn't exist for the requested entryload
756      */

757     public final int getPageType (EntryLoadRequest entryLoadRequest) {
758         JahiaPageInfo pageInfo = getPageInfoVersionIgnoreLanguage (entryLoadRequest, false);
759
760         if (pageInfo != null) {
761             return pageInfo.getPageType ();
762         }
763         if ( entryLoadRequest != null && entryLoadRequest.isVersioned() ){
764             // If there is no versioning entry, we should at least return the type
765
// of this page as it exist
766
try {
767                 if ( !this.mPageInfos.isEmpty() ){
768                     pageInfo = (JahiaPageInfo)this.mPageInfos.iterator().next();
769                     return pageInfo.getPageType();
770                 }
771             } catch ( Throwable JavaDoc t ){
772                 logger.debug(t);
773             }
774         }
775         return -1;
776     }
777
778
779
780     //-------------------------------------------------------------------------
781
/**
782      * Return the parent page unique identification number.
783      *
784      * @param jParams a ParamBean object to be able to specify for which
785      * version/language to retrieve the value of this method.
786      *
787      * @return Return the parent page ID.
788      */

789     public final int getParentID (EntryLoadRequest loadRequest) {
790         JahiaPageInfo pageInfo = getPageInfoVersionIgnoreLanguage (loadRequest, false);
791         if (pageInfo == null) {
792             return -1;
793         }
794         return pageInfo.getParentID ();
795     }
796
797     /**
798      * @param jParams
799      *
800      * @return
801      */

802     public final int getParentID (ParamBean jParams) {
803         if (jParams != null) {
804             return getParentID (jParams.getEntryLoadRequest ());
805         } else {
806             logger.debug ("FIXME : Method called with null ParamBean. Returning -1");
807             return -1;
808         }
809     }
810
811     public ContentObject getParent(EntryLoadRequest loadRequest)
812             throws JahiaException {
813         int pageFieldID = getPageFieldID(getID(), loadRequest);
814         ContentObject parent = null;
815         if (pageFieldID != -1) {
816             parent = ContentField.getField(pageFieldID);
817         } else {
818             return null;
819         }
820         return parent;
821     }
822
823     public int getPageFieldID(int pageID, EntryLoadRequest loadRequest) throws JahiaException {
824         return JahiaPageUtilsDB.getInstance().getPageFieldID(pageID, loadRequest);
825     }
826
827     // Define the same parent assertion.
828
public static final int SAME_PARENT = -1;
829
830     /**
831      * Verify if the page has same parent between its activated version and
832      * workflowed version. This case append especially when a page is moved.
833      * In this case, the activated page is NOT changed but the workflowed versions
834      * (will be created and) will have an other parents. This method test that.
835      *
836      * @return SAME_PARENT if page has same parents, otherwise return the ACTIVE parent
837      * page ID.
838      */

839     public int hasSameParentID () {
840         if (mActivePageInfos.isEmpty () || mStagingPageInfos.isEmpty ()) {
841             return SAME_PARENT;
842         }
843         JahiaPageInfo activePageInfo = (JahiaPageInfo) mActivePageInfos.get (
844                 mActivePageInfos.keySet ().iterator ().next ());
845         int activeParentID = activePageInfo.getParentID ();
846
847         JahiaPageInfo stagingPageInfo = null;
848         Iterator iterator = mStagingPageInfos.values().iterator();
849         int stagingParentID = activeParentID;
850         while ( iterator.hasNext() ){
851             stagingPageInfo = (JahiaPageInfo) iterator.next();
852             if ( stagingPageInfo.getVersionID()
853                  != EntryLoadRequest.DELETED_WORKFLOW_STATE ){
854                 stagingParentID = stagingPageInfo.getParentID ();
855             }
856         }
857
858         return activeParentID == stagingParentID ? SAME_PARENT : activeParentID;
859     }
860
861     //-------------------------------------------------------------------------
862
/**
863      * Return the remote URL in case the page is an external reference (a non
864      * Jahia page. If the page is not an external URL, "<no url>" is returned.
865      *
866      * @param jParams a ParamBean object to be able to specify for which
867      * version/language to retrieve the value of this method.
868      *
869      * @return Return the remote URL.
870      */

871     public final String JavaDoc getRemoteURL (EntryLoadRequest loadRequest) {
872         JahiaPageInfo pageInfo = getPageInfoVersionIgnoreLanguage (loadRequest, false);
873         if (pageInfo == null) {
874             return null;
875         }
876         return pageInfo.getRemoteURL ();
877     }
878
879     /**
880      * @param jParams
881      *
882      * @return
883      */

884     public final String JavaDoc getRemoteURL (ParamBean jParams) {
885         if (jParams != null) {
886             return getRemoteURL (jParams.getEntryLoadRequest ());
887         } else {
888             logger.debug ("FIXME : Method called with null ParamBean, returning null");
889             return null;
890         }
891     }
892
893
894     //-------------------------------------------------------------------------
895
/**
896      * Return the page title.
897      *
898      * @param jParams a ParamBean object to be able to specify for which
899      * version/language to retrieve the value of this method.
900      *
901      * @return Return the page title.
902      */

903     public final String JavaDoc getTitle (EntryLoadRequest loadRequest) {
904         return getTitle(loadRequest, true);
905     }
906
907     /**
908      * Returns the page title for the specified EntryLoadRequest, eventually
909      * encoding it for HTML output.
910      * @param loadRequest EntryLoadRequest
911      * @param htmlCompliant boolean
912      * @return String
913      */

914     public final String JavaDoc getTitle(EntryLoadRequest loadRequest, boolean htmlCompliant) {
915         JahiaPageInfo pageInfo = getPageInfoVersion (loadRequest, false, false);
916         if (pageInfo == null) {
917             return null;
918         }
919         if (htmlCompliant) {
920             return JahiaTools.text2html(pageInfo.getTitle());
921         } else {
922             return pageInfo.getTitle();
923         }
924     }
925
926     /**
927      * @param jParams
928      *
929      * @return
930      */

931     public final String JavaDoc getTitle (ParamBean jParams) {
932         if (jParams != null) {
933             return getTitle (jParams.getEntryLoadRequest ());
934         } else {
935             logger.debug ("FIXME : Method called with null ParamBean, returning null");
936             return null;
937         }
938     }
939
940     //-------------------------------------------------------------------------
941
/**
942      * Increments the page counter for this page.
943      *
944      * @param jParams a ParamBean object used to retrieve the internal
945      * property.
946      */

947     public final void incrementCounter (EntryLoadRequest loadRequest) {
948         // getPageInfoVersion(jParams, false).incrementCounter ();
949
int pageCounter = -1;
950         try {
951             PageProperty counterProperty = getPageLocalProperty ("counter");
952             String JavaDoc counterStr = null;
953             if (counterProperty != null) {
954                 counterStr = counterProperty.getValue();
955             }
956             if (counterStr != null) {
957                 pageCounter = Integer.parseInt (counterStr);
958             } else {
959                 pageCounter = 0;
960             }
961             if (pageCounter != -1) {
962                 setProperty ("counter", new Integer JavaDoc (pageCounter + 1).toString ());
963             }
964         } catch (JahiaException je) {
965             pageCounter = -1;
966         }
967     }
968
969     public final void incrementCounter (ParamBean jParams) {
970         if (jParams != null) {
971             incrementCounter (jParams.getEntryLoadRequest ());
972         } else {
973             logger.debug ("FIXME : Method called with null ParamBean, aborting...");
974             return;
975         }
976     }
977
978     //-------------------------------------------------------------------------
979
/**
980      * Set the new page defintion ID. The ID must point to a existing page
981      * definition.
982      *
983      * @param value The new page defintion ID.
984      * @param jParams a ParamBean object used to specify for which version
985      * we are setting the templateID.
986      *
987      * @throws JahiaException Throw this exception on any error. Only ERROR type error should
988      * be catched, all the other failures should be thrown further.
989      * @throws JahiaTemplateNotFoundException raised in case the template
990      * is not found.
991      */

992     public void setPageTemplateID (int value, EntryLoadRequest loadRequest)
993             throws JahiaException,
994             JahiaTemplateNotFoundException {
995         // check if the specified definition exists
996
ServicesRegistry services = ServicesRegistry.getInstance ();
997         if (services == null) {
998             throw new JahiaException ("Services registry error.",
999                     "Could not access the Services Registry!",
1000                    JahiaException.SERVICE_ERROR, JahiaException.CRITICAL_SEVERITY);
1001        }
1002
1003        JahiaPageTemplateService templateService = services.getJahiaPageTemplateService ();
1004
1005        if (templateService != null) {
1006            if (value != -1) {
1007                // set the new definition
1008

1009                Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1010                Enumeration pageInfosEnum = pageInfos.elements ();
1011                while (pageInfosEnum.hasMoreElements ()) {
1012                    JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1013                    // update the new definition ID in the page infos.
1014
curPageInfo.setPageType (TYPE_DIRECT);
1015                    curPageInfo.setPageTemplateID (value);
1016                }
1017            }
1018        } else {
1019            throw new JahiaException ("Page templates services error.",
1020                    "Could not access the Page Templates Services.",
1021                    JahiaException.SERVICE_ERROR, JahiaException.CRITICAL_SEVERITY);
1022        }
1023
1024    }
1025
1026    /**
1027     * @param value
1028     * @param jParams
1029     *
1030     * @throws JahiaException
1031     * @throws JahiaTemplateNotFoundException
1032     */

1033    public void setPageTemplateID (int value, ParamBean jParams)
1034            throws JahiaException,
1035            JahiaTemplateNotFoundException {
1036        if (jParams != null) {
1037            setPageTemplateID (value, jParams.getEntryLoadRequest ());
1038        } else {
1039            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1040            return;
1041        }
1042    }
1043
1044
1045    //-------------------------------------------------------------------------
1046
public void setPageTemplate (JahiaPageDefinition value, EntryLoadRequest loadRequest)
1047            throws JahiaException {
1048        if (value != null) {
1049            Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1050            Enumeration pageInfosEnum = pageInfos.elements ();
1051            while (pageInfosEnum.hasMoreElements ()) {
1052                JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1053                curPageInfo.setPageType (TYPE_DIRECT);
1054                curPageInfo.setPageTemplateID (value.getID ());
1055            }
1056        }
1057    }
1058
1059    /**
1060     * @param value
1061     * @param jParams
1062     *
1063     * @throws JahiaException
1064     */

1065    public void setPageTemplate (JahiaPageDefinition value, ParamBean jParams)
1066            throws JahiaException {
1067        if (jParams != null) {
1068            setPageTemplate (value, jParams.getEntryLoadRequest ());
1069        } else {
1070            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1071            return;
1072        }
1073    }
1074
1075    //-------------------------------------------------------------------------
1076
/**
1077     * Set the new internal link ID. This ID must be an existing page ID.
1078     *
1079     * @param value The new page link ID.
1080     * @param jParams a ParamBean object used to specify for which version/
1081     * language we are setting the PageLinkID (basically this makes sure we have
1082     * a staged version and that we have an entry for the current language).
1083     */

1084    public final void setPageLinkID (int value, EntryLoadRequest loadRequest) {
1085
1086        try {
1087            JahiaPage tempPage = ServicesRegistry.getInstance ().getJahiaPageService ().lookupPage (value, loadRequest);
1088            if (tempPage != null) {
1089                Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1090                Enumeration pageInfosEnum = pageInfos.elements ();
1091                while (pageInfosEnum.hasMoreElements ()) {
1092                    JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1093                    curPageInfo.setPageTemplateID (tempPage.getPageTemplateID ());
1094                    curPageInfo.setPageType (TYPE_LINK);
1095                    curPageInfo.setPageLinkID (value);
1096                }
1097            }
1098        } catch (JahiaException ex) {
1099            logger.debug ("Error while setting page link ID", ex);
1100        }
1101    }
1102
1103    /**
1104     * @param value
1105     * @param jParams
1106     */

1107    public final void setPageLinkID (int value, ParamBean jParams) {
1108        if (jParams != null) {
1109            setPageLinkID (value, jParams.getEntryLoadRequest ());
1110        } else {
1111            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1112            return;
1113        }
1114    }
1115
1116    //-------------------------------------------------------------------------
1117
/**
1118     * Change the page type. By changing this information, be aware to change
1119     * also the according remote URL or page link ID information. See the
1120     * methods {@link #setPageLinkID setPageLinkID()} and
1121     * {@link #setRemoteURL setRemoteURL()}.
1122     *
1123     * @param value The new page type.
1124     * @param jParams a ParamBean object used to specify for which version/
1125     * language we are setting the page type (basically this makes sure we have
1126     * a staged version and that we have an entry for the current language).
1127     */

1128    public final void setPageType (int value, EntryLoadRequest loadRequest)
1129            throws JahiaException {
1130        Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1131        Enumeration pageInfosEnum = pageInfos.elements ();
1132        while (pageInfosEnum.hasMoreElements ()) {
1133            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1134            curPageInfo.setPageType (value);
1135        }
1136    }
1137
1138    /**
1139     * @param value
1140     * @param jParams
1141     *
1142     * @throws JahiaException
1143     */

1144    public final void setPageType (int value, ParamBean jParams)
1145            throws JahiaException {
1146        if (jParams != null) {
1147            setPageType (value, jParams.getEntryLoadRequest ());
1148        } else {
1149            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1150            return;
1151        }
1152    }
1153
1154    //-------------------------------------------------------------------------
1155
/**
1156     * Set the new parent ID. This method should be used carefully, all the
1157     * subtree pages will move with the page. This method is used to move a
1158     * page. Basically it marks the old position for deletion, or really
1159     * deletes it if in only existed in staging.
1160     *
1161     * @param value The new parent page ID.
1162     * @param jParams a ParamBean object used to specify for which version/
1163     * language we are setting the ParentID (basically this makes sure we have
1164     * a staged version and that we have an entry for the current language).
1165     */

1166    public final void setParentID (int value, ParamBean jParams)
1167            throws JahiaException {
1168        setParentID (value, jParams.getUser (), jParams.getEntryLoadRequest ());
1169    }
1170
1171    //-------------------------------------------------------------------------
1172
/**
1173     * Set the new parent ID. This method should be used carefully, all the
1174     * subtree pages will move with the page. This method is used to move a
1175     * page. Basically it marks the old position for deletion, or really
1176     * deletes it if in only existed in staging.
1177     *
1178     * @param value The new parent page ID.
1179     * @param user
1180     * @param loadRequest
1181     *
1182     * @throws JahiaException
1183     */

1184    public final void setParentID (int value, JahiaUser user, EntryLoadRequest loadRequest)
1185            throws JahiaException {
1186
1187        // before we start changing the parent ID we have go to remove all the
1188
// content at the previous location. We do this by marking it for
1189
// deletion.
1190
ContentPageKey pageKey = new ContentPageKey (getID ());
1191        Map languageStates = getLanguagesStates (true);
1192        Set languageCodes = new HashSet (languageStates.keySet ());
1193        StateModificationContext stateModifContext = new
1194                StateModificationContext (new ContentPageKey (getID ()), languageCodes, false);
1195        /* removed because not sure it is necessary !
1196        if (stateModifContext.isObjectIDInPath(pageKey)) {
1197            // found a recursive call, let's abort now !
1198            logger.debug("Deletion marking aborted because of recursive call on object " + pageKey.toString() + " ! ");
1199            return;
1200        }
1201        */

1202        stateModifContext.pushObjectID (pageKey);
1203
1204        int parentFieldID = ServicesRegistry.getInstance().getJahiaPageService().
1205                            getPageFieldID(getID());
1206
1207        if (parentFieldID != -1) {
1208            // 1. Cut the page link in the parent field value
1209
ContentPageField contentPageField = (ContentPageField) ContentPageField.getField (
1210                    parentFieldID, true);
1211            if (contentPageField != null && contentPageField.getPageID () != value) {
1212                // PAGE_MOVE_LOGIC
1213
contentPageField.setValue(-1,Jahia.getThreadParamBean());
1214            }
1215        }
1216
1217        int activeParentID = getParentID (EntryLoadRequest.CURRENT);
1218        if (activeParentID == value) {
1219            logger.debug ("Moved page back to it's original position !");
1220        }
1221
1222        // now that we've marked the content, we can set the new parent ID.
1223
// we have set the parent to all lang, not only.
1224
Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1225        Enumeration pageInfosEnum = pageInfos.elements ();
1226        while (pageInfosEnum.hasMoreElements ()) {
1227            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1228            curPageInfo.setParentID (value);
1229
1230            // Note : we change staging page info without checking if this
1231
// staging page info is marked for delete or not.
1232
// If it is marked for delete, we should unmark it for deletion
1233
// which would have more meaning.
1234
curPageInfo.setVersionID(0);
1235        }
1236    }
1237
1238    /**
1239     * Set the ACL ID. Actually used when a page has change it's type. Passing from
1240     * URL link or DIRECT page to a Jahia page LINK type and vice versa.
1241     * WARNING ! Be careful with this method. Use it if it is really necessary
1242     * to change the ACL ID page.
1243     *
1244     * @param aclID The ACL ID to set.
1245     * @param jParams a ParamBean object used to specify for which version/
1246     * language we are setting the RemoteURL (basically this makes sure we have
1247     * a staged version and that we have an entry for the current language).
1248     *
1249     * @throws JahiaException
1250     */

1251    public final void setAclID (int aclID, EntryLoadRequest loadRequest)
1252            throws JahiaException {
1253        Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1254        Enumeration pageInfosEnum = pageInfos.elements ();
1255        while (pageInfosEnum.hasMoreElements ()) {
1256            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1257            curPageInfo.setAclID (aclID);
1258        }
1259    }
1260
1261    /**
1262     * @param aclID
1263     * @param jParams
1264     *
1265     * @throws JahiaException
1266     */

1267    public final void setAclID (int aclID, ParamBean jParams)
1268            throws JahiaException {
1269        if (jParams != null) {
1270            setAclID (aclID, jParams.getEntryLoadRequest ());
1271        } else {
1272            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1273            return;
1274        }
1275    }
1276
1277    //-------------------------------------------------------------------------
1278
/**
1279     * Set the new remote URL. The page type will change accordingly.
1280     *
1281     * @param value The new remoteURL.
1282     * @param jParams a ParamBean object used to specify for which version/
1283     * language we are setting the RemoteURL (basically this makes sure we have
1284     * a staged version and that we have an entry for the current language).
1285     */

1286    public final void setRemoteURL (String JavaDoc value, EntryLoadRequest loadRequest)
1287            throws JahiaException {
1288        Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1289        Enumeration pageInfosEnum = pageInfos.elements ();
1290        while (pageInfosEnum.hasMoreElements ()) {
1291            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1292            curPageInfo.setPageType (TYPE_URL);
1293            curPageInfo.setRemoteURL (value);
1294        }
1295    }
1296
1297    //-------------------------------------------------------------------------
1298
/**
1299     * Set the new remote URL. The page type will NOT change.
1300     *
1301     * @param value The new remoteURL.
1302     * @param jParams a ParamBean object used to specify for which version/
1303     * language we are setting the RemoteURL (basically this makes sure we have
1304     * a staged version and that we have an entry for the current language).
1305     */

1306    public final void setRemoteURLWithoutType (String JavaDoc value, EntryLoadRequest loadRequest)
1307            throws JahiaException {
1308        Vector pageInfos = getAllPageInfosForWrite (loadRequest);
1309        Enumeration pageInfosEnum = pageInfos.elements ();
1310        while (pageInfosEnum.hasMoreElements ()) {
1311            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosEnum.nextElement ();
1312            curPageInfo.setRemoteURLWithoutType(value);
1313        }
1314    }
1315    
1316    /**
1317     * @param value
1318     * @param jParams
1319     *
1320     * @throws JahiaException
1321     */

1322    public final void setRemoteURL (String JavaDoc value, ParamBean jParams)
1323            throws JahiaException {
1324        if (jParams != null) {
1325            setRemoteURL (value, jParams.getEntryLoadRequest ());
1326        } else {
1327            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1328            return;
1329        }
1330    }
1331
1332    //-------------------------------------------------------------------------
1333
/**
1334     * Change the page title.
1335     *
1336     * @param value String holding the new page title.
1337     * @param jParams a ParamBean object that specifies for which version and
1338     * language we want to set the title, as it may vary from one language to
1339     * another.
1340     */

1341    public final boolean setTitle (String JavaDoc value, EntryLoadRequest loadRequest) {
1342        if (value != null && !value.equals(getTitle(loadRequest))) {
1343            JahiaPageInfo jahiaPageInfo = getPageInfoVersion(loadRequest, true, false);
1344            jahiaPageInfo.setTitle(value);
1345            return true;
1346        }
1347        return false;
1348    }
1349
1350    /**
1351     * @param value
1352     * @param jParams
1353     */

1354    public final void setTitle (String JavaDoc
1355            value, ParamBean jParams) {
1356        if (jParams != null) {
1357            setTitle (value, jParams.getEntryLoadRequest ());
1358        } else {
1359            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1360            return;
1361        }
1362    }
1363
1364    //--------------------------------------------------------------------------
1365
/**
1366     * Set the titles for a set of languages
1367     *
1368     * @param languagesSet a set of languages as String for which to set the title.
1369     * @param Hashtable of key/value pair ( languageCode/title value )
1370     * @param ParamBean the jparams.
1371     */

1372    public final void setTitles (Set languagesSet, Hashtable titles,
1373                                 EntryLoadRequest loadRequest)
1374            throws JahiaException {
1375        Iterator iterator = languagesSet.iterator ();
1376        String JavaDoc languageCode = "";
1377        while (iterator.hasNext ()) {
1378            languageCode = (String JavaDoc) iterator.next ();
1379            setTitle (languageCode, (String JavaDoc) titles.get (languageCode), loadRequest);
1380        }
1381    }
1382
1383    /**
1384     * @param languagesSet
1385     * @param titles
1386     * @param jParams
1387     *
1388     * @throws JahiaException
1389     */

1390    public final void setTitles (Set languagesSet, Hashtable titles, ParamBean jParams)
1391            throws JahiaException {
1392        if (jParams != null) {
1393            setTitles (languagesSet, titles, jParams.getEntryLoadRequest ());
1394        } else {
1395            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1396            return;
1397        }
1398    }
1399
1400    /**
1401     * Set page titles for every language defined in the titles Hashtable.
1402     *
1403     * @param titles The titles Hashtable.
1404     * @param jParams The ParamBean.
1405     *
1406     * @throws JahiaException
1407     */

1408    public final void setTitles (Hashtable titles, EntryLoadRequest loadRequest)
1409            throws JahiaException {
1410        Enumeration languagesEnum = titles.keys ();
1411        while (languagesEnum.hasMoreElements ()) {
1412            String JavaDoc languageCode = (String JavaDoc) languagesEnum.nextElement ();
1413            setTitle (languageCode, (String JavaDoc) titles.get (languageCode), loadRequest);
1414        }
1415    }
1416
1417    /**
1418     * @param titles
1419     * @param jParams
1420     *
1421     * @throws JahiaException
1422     */

1423    public final void setTitles (Hashtable titles, ParamBean jParams)
1424            throws JahiaException {
1425        if (jParams != null) {
1426            setTitles (titles, jParams.getEntryLoadRequest ());
1427        } else {
1428            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1429            return;
1430        }
1431    }
1432
1433    //--------------------------------------------------------------------------
1434
/**
1435     * Set the title for a language code
1436     *
1437     * @param languageCode
1438     * @param title
1439     * @param ParamBean the jparams.
1440     */

1441    public final void setTitle (String JavaDoc languageCode, String JavaDoc title,
1442                                EntryLoadRequest loadRequest)
1443            throws JahiaException {
1444        if (!languageCode.equals (ContentField.SHARED_LANGUAGE)) {
1445            ArrayList locales = new ArrayList ();
1446            locales.add (LanguageCodeConverters
1447                    .languageCodeToLocale (languageCode));
1448            EntryLoadRequest languageLoadRequest = new EntryLoadRequest (
1449                    loadRequest.getWorkflowState (), loadRequest.getVersionID (), locales);
1450            this.setTitle (title, languageLoadRequest);
1451        }
1452    }
1453
1454    /**
1455     * @param languageCode
1456     * @param title
1457     * @param jParams
1458     *
1459     * @throws JahiaException
1460     */

1461    public final void setTitle (String JavaDoc languageCode, String JavaDoc title, ParamBean jParams)
1462            throws JahiaException {
1463        if (jParams != null) {
1464            setTitle (languageCode, title, jParams.getEntryLoadRequest ());
1465        } else {
1466            logger.debug ("FIXME : Method called with null ParamBean, aborting...");
1467            return;
1468        }
1469    }
1470
1471    /**
1472     * Constant associated with the getTitles method. Signify that this method should
1473     * return the last updated Jahia page titles.
1474     */

1475    public static final boolean LAST_UPDATED_TITLES = true;
1476
1477    /**
1478     * Constant associated with the getTitles method. Signify that this method should
1479     * only return the activated page titles.
1480     */

1481    public static final boolean ACTIVATED_PAGE_TITLES = false;
1482
1483    /**
1484     * Get all page titles in all languages. First check titles coming from the
1485     * active pages. If 'lastUpdatedTitles' is set, then check titles from the
1486     * staged page meaning that last input tiles are always returned.
1487     *
1488     * @param lastUpdatedTitles One of the LAST_UPDATED_TITLES or ACTIVATED_PAGE_TITLES
1489     * boolean constants. This boolean specifies if we should try to find a
1490     * staged version for a language if we couldn't find an active one.
1491     *
1492     * @return The last updated page titles. The object returned is a hashtable
1493     * containing String as keys that contain the language code, and the value
1494     * objects are String object containing the actual title in the language.
1495     */

1496    public Hashtable getTitles (boolean lastUpdatedTitles) {
1497        Hashtable titles = new Hashtable ();
1498        Iterator activePageInfosIt = mActivePageInfos.keySet ().iterator ();
1499
1500        while (activePageInfosIt.hasNext ()) {
1501            String JavaDoc languageCode = (String JavaDoc) activePageInfosIt.next ();
1502            String JavaDoc pageTitle = ((JahiaPageInfo) mActivePageInfos.get (languageCode)).getTitle ();
1503            titles.put (languageCode, pageTitle);
1504        }
1505        if (lastUpdatedTitles) {
1506            Iterator stagingPageInfosIt = mStagingPageInfos.keySet ().iterator ();
1507            while (stagingPageInfosIt.hasNext ()) {
1508                String JavaDoc languageCode = (String JavaDoc) stagingPageInfosIt.next ();
1509                String JavaDoc pageTitle = ((JahiaPageInfo) mStagingPageInfos.get (languageCode)).getTitle ();
1510                titles.put (languageCode, pageTitle);
1511            }
1512        }
1513
1514        if (!this.hasActiveEntries () && !this.hasStagingEntries ()) {
1515            try {
1516                // Deleted
1517
Vector langs = this.getSite().getLanguageSettings ();
1518                SiteLanguageSettings siteLanguageMapping = null;
1519                Enumeration enumeration = langs.elements ();
1520                while (enumeration.hasMoreElements ()) {
1521                    siteLanguageMapping = (SiteLanguageSettings) enumeration.nextElement ();
1522                    ContentObjectEntryState entryState =
1523                            new ContentObjectEntryState (
1524                                    ContentObjectEntryState.WORKFLOW_STATE_ACTIVE,
1525                                    0, siteLanguageMapping.getCode ());
1526                    EntryLoadRequest loadRequest = new EntryLoadRequest (entryState);
1527                    ContentDefinition definition =
1528                            ContentDefinition.getInstance (
1529                                    this.getDefinitionKey (loadRequest));
1530
1531                    String JavaDoc title = "";
1532                    if (definition != null) {
1533                        title = definition.getTitle (this, entryState);
1534                    }
1535                    if (title != null) {
1536                        titles.put (siteLanguageMapping.getCode (), title);
1537                    }
1538                }
1539            } catch (Throwable JavaDoc t) {
1540                logger.debug ("Exception : retrieving titles or deleted page", t);
1541            }
1542        }
1543
1544        return titles;
1545    }
1546
1547    public JahiaSite getSite ()
1548            throws JahiaException {
1549        int siteID = getJahiaID ();
1550        JahiaSite site = ServicesRegistry.getInstance ().getJahiaSitesService ().getSite (
1551                siteID);
1552        return site;
1553    }
1554
1555    //-------------------------------------------------------------------------
1556
/**
1557     * Return the page URL
1558     * for backward compatibility.
1559     *
1560     * @param jParams a ParamBean object used to generate all the URLs using
1561     * the ParamBean URL generation methods. The ParamBean is also used to
1562     * retrieve a RemoteURL if we have that type.
1563     *
1564     * @return Return the page URL string.
1565     *
1566     * @throws JahiaException thrown in there were problems while generating
1567     * the URLs
1568     */

1569    public String JavaDoc getUrl (ParamBean jParams)
1570            throws JahiaException {
1571        return getURL (jParams);
1572    } // end getUrl
1573

1574
1575    //-------------------------------------------------------------------------
1576
/**
1577     * Return the page URL with the given language code.
1578     *
1579     * @param jParams a ParamBean object used to generate all the URLs using
1580     * the ParamBean URL generation methods. The ParamBean is also used to
1581     * retrieve a RemoteURL if we have that type.
1582     * @param languageCode The 'iso639' composed with the 'iso3166' language code.
1583     *
1584     * @return Return the page URL string.
1585     *
1586     * @throws JahiaException thrown in there were problems while generating
1587     * the URLs
1588     */

1589    public String JavaDoc getURL (ParamBean jParams, String JavaDoc languageCode)
1590            throws JahiaException {
1591        String JavaDoc outURL = "";
1592        switch (getPageType (jParams.getEntryLoadRequest ())) {
1593            case (TYPE_DIRECT):
1594                outURL = jParams.composePageUrl (getID (), languageCode);
1595                break;
1596            case (TYPE_LINK):
1597                int linkPageID = -1;
1598                try {
1599                    linkPageID = getPageLinkID (jParams.getEntryLoadRequest ());
1600                    if (linkPageID != -1) {
1601                        ContentPage linkPage = ContentPage.getPage (linkPageID, false);
1602                        // require at least read access
1603
if (linkPage.checkReadAccess (jParams.getUser ())) {
1604                            outURL = jParams.composePageUrl (linkPageID, languageCode);
1605                        } else {
1606                            //logger.debug("No read access to linked page [" + linkPageID + "]");
1607
}
1608                    }
1609                } catch (Throwable JavaDoc t) {
1610                    logger.debug ("Exception creating link url with page[" + linkPageID + "]",
1611                            t);
1612                }
1613                break;
1614            case (TYPE_URL):
1615                outURL = getRemoteURL (jParams.getEntryLoadRequest ());
1616                break;
1617        }
1618        return outURL;
1619    }
1620
1621    /**
1622     * Return the page URL in the current language.
1623     *
1624     * @param jParams ;)
1625     *
1626     * @return Return the page URL string.
1627     *
1628     * @throws JahiaException
1629     */

1630    public String JavaDoc getURL (ParamBean jParams)
1631            throws JahiaException {
1632        return getURL (jParams, null);
1633    }
1634
1635    //-------------------------------------------------------------------------
1636
/**
1637     * Return the page path. The page path consist of all the parent pages of
1638     * the specified page until the site's root page.
1639     *
1640     * @param jParams a ParamBean object used to load pages in the path.
1641     *
1642     * @return Return a enumeration of JahiaPage objects. The returned
1643     * Enumeration is always non-null, but might have no pages if the
1644     * specified page has not childs, or if no childs matching the
1645     * loading flag were found.
1646     *
1647     * @throws JahiaException in the case that we have problems loading the
1648     * pages from the persistant storage
1649     */

1650    public Enumeration getContentPagePath (EntryLoadRequest loadRequest, String JavaDoc operationMode,
1651                                    JahiaUser user)
1652            throws JahiaException {
1653        Vector thePath = ServicesRegistry.getInstance ().getJahiaPageService ().getContentPagePath (getID (), loadRequest, operationMode, user);
1654        if (thePath != null) {
1655            return thePath.elements ();
1656        }
1657        return null;
1658    } // end getPath
1659

1660    /**
1661     * @param jParams
1662     *
1663     * @return
1664     *
1665     * @throws JahiaException
1666     */

1667    public Enumeration getContentPagePath (ParamBean jParams)
1668            throws JahiaException {
1669        if (jParams != null) {
1670            return getContentPagePath (jParams.getEntryLoadRequest (), jParams.getOperationMode (),
1671                    jParams.getUser ());
1672        } else {
1673            logger.debug ("FIXME : Method called with null ParamBean, returning null");
1674            return null;
1675        }
1676    }
1677
1678
1679
1680    //-------------------------------------------------------------------------
1681
/**
1682     * Return the page path. The page path consist of all the parent pages of
1683     * the specified page until the site's root page.
1684     *
1685     * @param levels an integer specifying the offset of levels to retrieve.
1686     * So if the page is a depth level 5 and we specify that we want to retrieve
1687     * only 2 levels, only levels 4 and 5 will be returned by this method.
1688     * @param jParams a ParamBean object used to load pages in the path.
1689     *
1690     * @return Return a enumeration of JahiaPage objects. The returned
1691     * Enumeration is always non-null, but might have no pages if the
1692     * specified page has not childs, or if no childs matching the
1693     * loading flag were found.
1694     *
1695     * @throws JahiaException in the case that we have problems loading the
1696     * pages from the persistant storage
1697     */

1698    public Enumeration getContentPagePath (int levels, ParamBean jParams)
1699            throws JahiaException {
1700        Vector thePath = ServicesRegistry.getInstance ().getJahiaPageService ().getContentPagePath (getID (), jParams.getEntryLoadRequest (),
1701                jParams.getOperationMode (), jParams.getUser ());
1702        if (thePath != null) {
1703            int fromIndex = 0;
1704            if ((thePath.size () - levels) > 0) {
1705                fromIndex = thePath.size () - levels;
1706            }
1707            List theShortPathList = thePath.subList (fromIndex, thePath.size ());
1708            Vector theShortPathVector = new Vector (theShortPathList);
1709            return theShortPathVector.elements ();
1710        }
1711        return null;
1712    } // end getPath
1713

1714    //-------------------------------------------------------------------------
1715
/**
1716     * Return the page path. The page path consist of all the parent pages of
1717     * the specified page until the site's root page.
1718     *
1719     * @param jParams a ParamBean object used to load pages in the path.
1720     *
1721     * @return Return a enumeration of JahiaPage objects. The returned
1722     * Enumeration is always non-null, but might have no pages if the
1723     * specified page has not childs, or if no childs matching the
1724     * loading flag were found.
1725     *
1726     * @throws JahiaException in the case that we have problems loading the
1727     * pages from the persistant storage
1728     */

1729    public Enumeration getPagePath (EntryLoadRequest loadRequest, String JavaDoc operationMode,
1730                                    JahiaUser user)
1731            throws JahiaException {
1732        Vector thePath = ServicesRegistry.getInstance ().getJahiaPageService ().getPagePath (getID (), loadRequest, operationMode, user);
1733        if (thePath != null) {
1734            return thePath.elements ();
1735        }
1736        return null;
1737    } // end getPath
1738

1739    /**
1740     * @param jParams
1741     *
1742     * @return
1743     *
1744     * @throws JahiaException
1745     */

1746    public Enumeration getPagePath (ParamBean jParams)
1747            throws JahiaException {
1748        if (jParams != null) {
1749            return getPagePath (jParams.getEntryLoadRequest (), jParams.getOperationMode (),
1750                    jParams.getUser ());
1751        } else {
1752            logger.debug ("FIXME : Method called with null ParamBean, returning null");
1753            return null;
1754        }
1755    }
1756
1757
1758
1759    //-------------------------------------------------------------------------
1760
/**
1761     * Return the page path. The page path consist of all the parent pages of
1762     * the specified page until the site's root page.
1763     *
1764     * @param levels an integer specifying the offset of levels to retrieve.
1765     * So if the page is a depth level 5 and we specify that we want to retrieve
1766     * only 2 levels, only levels 4 and 5 will be returned by this method.
1767     * @param jParams a ParamBean object used to load pages in the path.
1768     *
1769     * @return Return a enumeration of JahiaPage objects. The returned
1770     * Enumeration is always non-null, but might have no pages if the
1771     * specified page has not childs, or if no childs matching the
1772     * loading flag were found.
1773     *
1774     * @throws JahiaException in the case that we have problems loading the
1775     * pages from the persistant storage
1776     */

1777    public Enumeration getPagePath (int levels, ParamBean jParams)
1778            throws JahiaException {
1779        Vector thePath = ServicesRegistry.getInstance ().getJahiaPageService ().getPagePath (getID (), jParams.getEntryLoadRequest (),
1780                jParams.getOperationMode (), jParams.getUser ());
1781        if (thePath != null) {
1782            int fromIndex = 0;
1783            if ((thePath.size () - levels) > 0) {
1784                fromIndex = thePath.size () - levels;
1785            }
1786            List theShortPathList = thePath.subList (fromIndex, thePath.size ());
1787            Vector theShortPathVector = new Vector (theShortPathList);
1788            return theShortPathVector.elements ();
1789        }
1790        return null;
1791    } // end getPath
1792

1793    //-------------------------------------------------------------------------
1794
/**
1795     * Return an enumeration holding all the child pages of the specified page.
1796     * The loading flag filters the kind of pages to return.
1797     *
1798     * @param jParams a ParamBean object used to specify which pages to load
1799     * from persistant storage
1800     *
1801     * @return Return an Enumeration of JahiaPage objects. Return null if not
1802     * the current page has not childs.
1803     *
1804     * @throws JahiaException Return this exception if any failure occured.
1805     */

1806    public Enumeration getChilds (ParamBean jParams)
1807            throws JahiaException {
1808        Vector childs = ServicesRegistry.getInstance ().getJahiaPageService ()
1809            .getPageChilds (getID (), PageLoadFlags.ALL, jParams);
1810
1811        if (childs != null) {
1812            return childs.elements ();
1813        }
1814        return null;
1815    } // end getChilds
1816

1817    /**
1818     * Return an enumeration holding all the child pages of the specified page.
1819     * The loading flag filters the kind of pages to return. This method checks
1820     * the rights for a user and loads only the pages a user is allowed to
1821     * see.
1822     *
1823     * @param user a JahiaUser object for which to check the rights on the
1824     * pages
1825     * @param jParams a ParamBean object used to specify which pages to load
1826     * from persistant storage
1827     *
1828     * @return an Enumeration of JahiaPage objects that are the childs of this
1829     * page
1830     *
1831     * @throws JahiaException thrown in the case we have problems while loading
1832     * data from the persistent storage
1833     */

1834    public Enumeration getChilds (JahiaUser user)
1835            throws JahiaException {
1836        Vector childs = ServicesRegistry.getInstance().getJahiaPageService()
1837            .getPageChilds (getID (), PageLoadFlags.ALL, user);
1838
1839        // logger.debug ("Nb child found " + childs.size());
1840
if (childs != null) {
1841            return childs.elements ();
1842        }
1843        return null;
1844    } // end getChilds
1845

1846    /**
1847     * @param user
1848     * @param jParams
1849     *
1850     * @return
1851     *
1852     * @throws JahiaException
1853     */

1854    public Enumeration getChilds (JahiaUser user, ParamBean jParams)
1855            throws JahiaException {
1856        return getChilds (user);
1857    }
1858
1859    public ArrayList getChilds (JahiaUser user,
1860                                EntryLoadRequest loadRequest)
1861            throws JahiaException {
1862        ArrayList resultList = new ArrayList ();
1863
1864        switch (getPageType (loadRequest)) {
1865            case JahiaPage.TYPE_DIRECT:
1866                // first let's add all the fields that are directly attached to
1867
// the page.
1868
Vector nonContainerFieldIDs = ServicesRegistry.getInstance().getJahiaFieldService()
1869                        .getNonContainerFieldIDsInPageByWorkflowState(getID(), loadRequest);
1870                Enumeration nonContainerFieldIDEnum = nonContainerFieldIDs.elements();
1871                while (nonContainerFieldIDEnum.hasMoreElements()) {
1872                    Integer JavaDoc curFieldID = (Integer JavaDoc) nonContainerFieldIDEnum.nextElement();
1873                    ContentField curField = ContentField.getField(curFieldID.intValue());
1874                    if (curField != null) {
1875                        resultList.add(curField);
1876                    }
1877                }
1878
1879                // now let's add all the container lists that are the direct
1880
// children of this page (subcontainers lists are NOT included here !)
1881
SortedSet containerListIDs = ServicesRegistry.getInstance().getJahiaContainersService()
1882                        .getAllPageTopLevelContainerListIDs(getID(), loadRequest);
1883                Iterator containerListIDIter = containerListIDs.iterator();
1884                while (containerListIDIter.hasNext()) {
1885                    Integer JavaDoc curContainerListID = (Integer JavaDoc) containerListIDIter.next();
1886                    ContentContainerList curContainerList = ContentContainerList.getContainerList(curContainerListID
1887                            .intValue());
1888                    if (curContainerList != null) {
1889                        resultList.add(curContainerList);
1890                    }
1891                }
1892                break;
1893            case JahiaPage.TYPE_LINK:
1894            case JahiaPage.TYPE_URL:
1895                break;
1896        }
1897
1898        return resultList;
1899    }
1900
1901    public ContentObject getParent (JahiaUser user,
1902                                    EntryLoadRequest loadRequest,
1903                                    String JavaDoc operationMode)
1904            throws JahiaException {
1905        int pageFieldID = JahiaPageUtilsDB.getInstance ().getPageFieldID (getID (), loadRequest);
1906        if (pageFieldID != -1) {
1907            return ContentField.getField (pageFieldID);
1908        } else {
1909            return null;
1910        }
1911    }
1912
1913    /**
1914     * Return an enumeration holding all the child PAGE(!) of the specified page.
1915     * This method checks the rights for a user and loads only the pages a user
1916     * is allowed to see.
1917     *
1918     * @param user a JahiaUser object for which to check the rights on the
1919     * pages
1920     *
1921     * @return an Enumeration of JahiaPageContent objects that are the childs of this
1922     * page
1923     *
1924     * @throws JahiaException thrown in the case we have problems while loading
1925     * data from the persistent storage
1926     */

1927    public Enumeration getDirectContentPageChilds (JahiaUser user, int pageInfosFlags,
1928                                                   String JavaDoc languageCode)
1929            throws JahiaException {
1930        Vector childs = ServicesRegistry.getInstance ().getJahiaPageService ().getDirectContentPageChilds (getID (), user, pageInfosFlags,
1931                languageCode);
1932        if (childs != null) {
1933            return childs.elements ();
1934        }
1935        return null;
1936    }
1937
1938    /**
1939     * Return an enumeration holding all the child PAGE(!) of the specified page.
1940     * This method checks the rights for a user and loads only the pages a user
1941     * is allowed to see.
1942     *
1943     * @param user a JahiaUser object for which to check the rights on the
1944     * pages
1945     * @param pageInfosFlags
1946     * @param languageCode
1947     * @param directPageOnly
1948     *
1949     * @return an Enumeration of JahiaPageContent objects that are the childs of this
1950     * page
1951     *
1952     * @throws JahiaException thrown in the case we have problems while loading
1953     * data from the persistent storage
1954     */

1955    public Enumeration getContentPageChilds (JahiaUser user, int pageInfosFlags,
1956                                             String JavaDoc languageCode, boolean directPageOnly)
1957            throws JahiaException {
1958        Vector childs = ServicesRegistry.getInstance ().getJahiaPageService ().getContentPageChilds (getID (), user, pageInfosFlags,
1959                languageCode, directPageOnly);
1960        if (childs != null) {
1961            return childs.elements ();
1962        }
1963        return null;
1964    }
1965
1966    //-------------------------------------------------------------------------
1967
/**
1968     * Compare between two objects, sort by their name
1969     *
1970     * @param c1 left-side object
1971     * @param c2 right-side object
1972     *
1973     * @return <0 if c1 < c2, 0 if c1=c2, >0 if c1>c2
1974     *
1975     * @throws ClassCastException if the objects where not of type JahiaPage.
1976     */

1977    public int compare (Object JavaDoc c1, Object JavaDoc c2) throws ClassCastException JavaDoc {
1978
1979        return ((JahiaPage) c1)
1980                .getTitle ().toLowerCase ()
1981                .compareTo (((JahiaPage) c2).getTitle ().toLowerCase ());
1982
1983    }
1984
1985
1986    //-------------------------------------------------------------------------
1987
/**
1988     * Generates a String containing a status and debug information about this
1989     * ContentPage object.
1990     *
1991     * @return a String containing most of the internal variable states
1992     */

1993    public String JavaDoc toString () {
1994        StringBuffer JavaDoc output = new StringBuffer JavaDoc ();
1995        output.append ("Detail of ContentPage [" + getID () + "] :\n");
1996        output.append ("Displaying JahiaPageInfo vector : ");
1997        Iterator pageInfoIter = mPageInfos.iterator ();
1998        int counter = 0;
1999        while (pageInfoIter.hasNext ()) {
2000            output.append ("JahiaPageInfo#");
2001            output.append (counter);
2002            output.append (":");
2003            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
2004            output.append (curPageInfo.toString ());
2005            counter++;
2006        }
2007        output.append ("end of ContentPage display.\n");
2008
2009        return output.toString ();
2010    }
2011
2012    /**
2013     * Purges this page and ALL it's related content. This is the ultimate
2014     * deletion method. Please use carefully. This destroys everything, including
2015     * versions, staging, etc...
2016     *
2017     * @throws JahiaException in case there was an error removing some content
2018     * from database.
2019     */

2020    public void purge (EntryLoadRequest loadRequest) throws JahiaException {
2021
2022        ServicesRegistry sr = ServicesRegistry.getInstance ();
2023
2024        switch (getPageType (loadRequest)) {
2025
2026            case JahiaPage.TYPE_DIRECT:
2027
2028                // we must now mark all page related content for deletion, that is to
2029
// say :
2030

2031                // 1. all fields on the page
2032
sr.getJahiaFieldService ().purgePageFields (getID ());
2033
2034                // 2. all container lists on the page
2035
sr.getJahiaContainersService ().purgePageContainerLists (getID ());
2036
2037                break;
2038            case JahiaPage.TYPE_LINK:
2039                break;
2040            case JahiaPage.TYPE_URL:
2041                break;
2042        }
2043
2044        // first we must check if there are active versions for the page info
2045
// data. If not, we simply delete directly the existing staging entries
2046

2047        /** @todo FIXME : this doesn't include versioned or deleted page infos,
2048         * we might need to include them too.
2049         */

2050
2051        Iterator allPageInfoIter = mPageInfos.iterator ();
2052        Set deletedACLs = new HashSet ();
2053        while (allPageInfoIter.hasNext ()) {
2054            JahiaPageInfo curPageInfo = (JahiaPageInfo) allPageInfoIter.next ();
2055            if (curPageInfo.getPageType () != JahiaPage.TYPE_LINK) {
2056                try {
2057                    JahiaBaseACL acl = new JahiaBaseACL (curPageInfo.getAclID ());
2058                    if (acl != null && !deletedACLs.contains (new Integer JavaDoc (acl.getID ()))) {
2059                        deletedACLs.add (new Integer JavaDoc (acl.getID ()));
2060                        acl.delete ();
2061                        acl = null;
2062                    }
2063                } catch (Throwable JavaDoc t) {
2064                    logger.debug (
2065                            "Exception when deleting acl[" + curPageInfo.getAclID () + "] of page[" + curPageInfo.getID () + "]",
2066                            t);
2067                }
2068            }
2069            deleteEntry (curPageInfo);
2070        }
2071
2072    }
2073
2074    /**
2075     * Returns a local page property. This method does not do recursive upwards
2076     * checking in the parent pages, but only checks locally.
2077     *
2078     * @param name the name of the property to retrieve
2079     *
2080     * @return a PageProperty object that may contain multiple language versions
2081     *
2082     * @throws JahiaException thrown in case we have trouble loading the
2083     * properties from the persistant storage
2084     */

2085    public PageProperty getPageLocalProperty (String JavaDoc name)
2086            throws JahiaException {
2087        Map pageProperties = ServicesRegistry.getInstance ()
2088                .getJahiaPageService ().getPageProperties (this.getID ());
2089        if (pageProperties != null) {
2090            PageProperty prop = (PageProperty) pageProperties.get (name);
2091            return prop;
2092        } else {
2093            logger.debug ("Error accessing page property " + name +
2094                    " probably doesn't exist yet...");
2095            return null;
2096        }
2097    }
2098
2099    /**
2100     * Retrieves a page property value. If the property couldn't be found for
2101     * this page, and that this page has a parent, this method will go up
2102     * the page hierarchy to look for this property. This method retrieves the
2103     * default value for a property, ignoring multi-language values if they
2104     * exist.
2105     *
2106     * @param name a String containing the name of the page property to
2107     * return.
2108     * @param jParams a ParamBean object used to load the parent pages in the
2109     * case we do not find the property in this page.
2110     *
2111     * @return a String containing the value of the page property or null if
2112     * the property couldn't be found.
2113     *
2114     * @throws JahiaException raised if there was a problem accessing the
2115     * backend systems that contain the properties
2116     */

2117    public String JavaDoc getProperty (String JavaDoc name, EntryLoadRequest loadRequest)
2118            throws JahiaException {
2119        PageProperty curProp = getPageLocalProperty (name);
2120        if (curProp != null) {
2121            return curProp.getValue ();
2122        } else {
2123            // we could find it locally, let's try to find it in the parent if
2124
// this object has one.
2125
if (getParentID (loadRequest) > 0) {
2126                // we are not in the case of the root page or a page without
2127
// a parent
2128
ContentPage parentPage = ServicesRegistry.getInstance ().getJahiaPageService ().lookupContentPage (
2129                        getParentID (loadRequest), true);
2130                if (parentPage != null) {
2131                    // let's recursively look for the property in parent
2132
// pages
2133
return parentPage.getProperty (name, loadRequest);
2134                }
2135            }
2136            return null;
2137        }
2138    }
2139
2140    public String JavaDoc getProperty (String JavaDoc name, ParamBean jParams)
2141            throws JahiaException {
2142        if (jParams != null) {
2143            return getProperty (name, jParams.getEntryLoadRequest ());
2144        } else {
2145            logger.debug ("FIXME : Method called with null ParamBean, returning null");
2146            return null;
2147        }
2148    }
2149
2150    /**
2151     * Retrieves the page property value corresponding to the specified
2152     * language code. If the property is not defined for this page, this
2153     * method will try to walk up the page hierarchy to find it.
2154     *
2155     * @param name the name of the property to retrieve
2156     * @param languageCode the RFC 3066 language code for which to retrieve
2157     * the page property value
2158     * @param jParams a ParamBean object used to load the parent pages in the
2159     * case we do not find the property in this page.
2160     *
2161     * @return a String containing the property value for the given language OR
2162     * the default value if it couldn't be found.
2163     *
2164     * @throws JahiaException raised if there was a problem accessing the
2165     * backend systems that contain the properties
2166     */

2167    public String JavaDoc getProperty (String JavaDoc name, String JavaDoc languageCode, ParamBean jParams)
2168            throws JahiaException {
2169        PageProperty curProp = getPageLocalProperty (name);
2170        if (curProp != null) {
2171            return curProp.getValue (languageCode);
2172        } else {
2173            // we could find it locally, let's try to find it in the parent if
2174
// this object has one.
2175
if (getParentID (jParams.getEntryLoadRequest ()) > 0) {
2176                // we are not in the case of the root page or a page without
2177
// a parent
2178
JahiaPage parentPage = ServicesRegistry.getInstance ().getJahiaPageService ().lookupPage (
2179                        getParentID (jParams.getEntryLoadRequest ()),
2180                        jParams.getEntryLoadRequest (), jParams.getOperationMode (),
2181                        jParams.getUser (), true);
2182                if (parentPage != null) {
2183                    // let's recursively look for the property in parent
2184
// pages
2185
return parentPage.getProperty (name, languageCode);
2186                }
2187            }
2188            return null;
2189        }
2190    }
2191
2192    /**
2193     * Sets a page property value. This updates both the in-memory and
2194     * persistant systems simultaneously so it might have a performance
2195     * impact. This sets the default value of the property.
2196     *
2197     * @param name the name of the page property to be set
2198     * @param value the value of the page property
2199     *
2200     * @throws JahiaException raised if there was a problem accessing the
2201     * backend systems that contain the properties
2202     */

2203    public synchronized void setProperty (String JavaDoc name, String JavaDoc value)
2204            throws JahiaException {
2205        PagePropertyDB.getInstance ().setPageProperty (getID(), name, value);
2206
2207        ServicesRegistry.getInstance().getJahiaPageService().updateContentPageCache(this);
2208    }
2209
2210    /**
2211     * Sets a page property value. This updates both the in-memory and
2212     * persistant systems simultaneously so it might have a performance
2213     * impact. This sets the value for a given language code of the page
2214     * property
2215     *
2216     * @param name the name of the page property to be set
2217     * @param languageCode the RFC 3066 language code for which to store
2218     * the property value.
2219     * @param value the value of the page property
2220     *
2221     * @throws JahiaException raised if there was a problem accessing the
2222     * backend systems that contain the properties
2223     */

2224    public synchronized void setProperty (String JavaDoc name, String JavaDoc languageCode, String JavaDoc value)
2225            throws JahiaException {
2226        PagePropertyDB.getInstance ().setPageProperty (getID(), name, languageCode, value);
2227        
2228        ServicesRegistry.getInstance().getJahiaPageService().updateContentPageCache(this);
2229    }
2230
2231    /**
2232     * Remove a property. This updates both the in-memory and
2233     * persistant systems simultaneously so it might have a performance
2234     * impact.
2235     *
2236     * @param name the name of the page property to be removed
2237     *
2238     * @throws JahiaException raised if there was a problem accessing the
2239     * backend systems that contain the properties
2240     */

2241    public void removeProperty (String JavaDoc name)
2242            throws JahiaException {
2243        PageProperty targetProperty = null;
2244        Map pageProperties = ServicesRegistry.getInstance ()
2245                .getJahiaPageService ().getPageProperties (this.getID ());
2246        if (pageProperties != null) {
2247            targetProperty = getPageLocalProperty(name);
2248            if (targetProperty != null) {
2249                pageProperties.remove(name);
2250                PagePropertyDB.getInstance().removePageProperty(targetProperty);
2251            }
2252        }
2253        ServicesRegistry.getInstance().getJahiaPageService().updateContentPageCache(this);
2254    }
2255
2256    /**
2257     * Determines with which JahiaPageInfo object we must work for a request.
2258     * This is different depending on whether we are trying to read values or
2259     * write them.
2260     * In the case of reading them, we want to resolve according to language
2261     * preferences, retrieved from the ParamBean.getLocales method. We will
2262     * also resolve whether to retrieve the active or staging version to read.
2263     * In the write case we want to write to a specific language, and a specific
2264     * version for writing which will be in staging mode.
2265     *
2266     * @param jParams a ParamBean object used to retrieve the Locale list as
2267     * well as the information as to which version to load between the active
2268     * and the staged version. null is accepted as a value, which means we do
2269     * not care which JahiaPageInfo is returned. This is mostly used to access
2270     * properties that have the same value in all versions/languages
2271     * @param isWrite a boolean indicating if we want to retrieve a version for
2272     * writing or just for reading (changes the resolving algorithm !)
2273     *
2274     * @return a JahiaPageInfo resolved according to the above-explained rules.
2275     */

2276    protected JahiaPageInfo getPageInfoVersion (EntryLoadRequest loadRequest, boolean isWrite,
2277                                                boolean ignoreLanguage) {
2278        if (mPageInfos.size () < 1) {
2279            logger.debug ("No page info for page, can't access database data");
2280            return null;
2281        }
2282
2283        if (isWrite) {
2284            JahiaPageInfo writeInfo = null;
2285            try {
2286                writeInfo = getPageInfoVersionForWrite (loadRequest);
2287            } catch (JahiaException je) {
2288                logger.debug ("Error while retrieving page info for writing", je);
2289            }
2290            return writeInfo;
2291        }
2292
2293        JahiaPageInfo curInfo = null;
2294
2295        if (loadRequest != null) {
2296            if (loadRequest.getWorkflowState () <= 0) {
2297                // we are in the case of an archived version, let's load it
2298
// just for this case. None of these operations are cached.
2299
try {
2300                    loadVersioningEntryStates ();
2301                } catch (JahiaException je) {
2302                    logger.debug ("Exception loading versioning entries", je);
2303                }
2304            }
2305            Vector pageInfos = new Vector (mPageInfos);
2306            curInfo =
2307                    (JahiaPageInfo) ServicesRegistry.getInstance ().getJahiaVersionService ()
2308                    .resolveEntry (pageInfos, loadRequest, ignoreLanguage);
2309            /*
2310            if ( curInfo == null && jParams.getEntryLoadRequest().isStaging() ){
2311                EntryLoadRequest entryLoadRequest = new EntryLoadRequest(EntryLoadRequest.STAGING_WORKFLOW_STATE,
2312                                                                         jParams.getEntryLoadRequest().getVersionID(),
2313                                                                         jParams.getEntryLoadRequest().getLocales());
2314                curInfo = (JahiaPageInfo) ServicesRegistry.getInstance().getJahiaVersionService().resolveEntry(mPageInfos, entryLoadRequest);
2315            }
2316            */

2317            if (curInfo == null) {
2318                // FIXME : Fix the case where no page in all language !!!!
2319
// curInfo = (JahiaPageInfo) ServicesRegistry.getInstance().getJahiaVersionService().resolveEntry(mPageInfos, EntryLoadRequest.CURRENT);
2320
}
2321        } else {
2322
2323            // logger.debug( "No ParamBean passed, returning any page data for page...");
2324
/** @todo FIXME this is ugly and random, we MUST do better ! */
2325            Iterator pageInfoIter = mPageInfos.iterator ();
2326            if (pageInfoIter.hasNext ()) {
2327                curInfo = (JahiaPageInfo) pageInfoIter.next ();
2328            }
2329        }
2330
2331        // resolving the case in which the entry load request is equals to "shared"
2332
if (curInfo == null && (loadRequest.getFirstLocale (true) == null)) {
2333            // no language specified
2334
// we return the first entry matching the request but no matter in which language it is.
2335
int workflow_state = loadRequest.getWorkflowState ();
2336            if (workflow_state <= 0) {
2337                // @todo loading versioned entries
2338
}
2339            if (curInfo == null
2340                    && workflow_state == ContentObjectEntryState.WORKFLOW_STATE_START_STAGING) {
2341
2342                if (mStagingPageInfos.values ().iterator ().hasNext ()) {
2343                    curInfo = (JahiaPageInfo) mStagingPageInfos.values ().iterator ().next ();
2344                }
2345                if (curInfo == null && mActivePageInfos.values ().iterator ().hasNext ()) {
2346                    curInfo = (JahiaPageInfo) mActivePageInfos.values ().iterator ().next ();
2347                }
2348            }
2349            if (curInfo == null
2350                    && workflow_state == ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) {
2351                if (mActivePageInfos.values ().iterator ().hasNext ()) {
2352                    curInfo = (JahiaPageInfo) mActivePageInfos.values ().iterator ().next ();
2353                }
2354            }
2355        }
2356        return curInfo;
2357    }
2358
2359    /**
2360     * If getPageInfoVersion(jParams,isWrite) return null, try again with a
2361     * an entryLoadRequest with only one language (SHARED), that is, try to get
2362     * an active or staging page info no matter what language it is.
2363     *
2364     * @param jParams a ParamBean object used to retrieve the Locale list as
2365     * well as the information as to which version to load between the active
2366     * and the staged version. null is accepted as a value, which means we do
2367     * not care which JahiaPageInfo is returned. This is mostly used to access
2368     * properties that have the same value in all versions/languages
2369     * @param isWrite a boolean indicating if we want to retrieve a version for
2370     * writing or just for reading (changes the resolving algorithm !)
2371     *
2372     * @return a JahiaPageInfo resolved according to the above-explained rules.
2373     */

2374    protected JahiaPageInfo getPageInfoVersionIgnoreLanguage (EntryLoadRequest loadRequest,
2375                                                              boolean isWrite) {
2376        JahiaPageInfo pageInfo = getPageInfoVersion (loadRequest, isWrite, true);
2377        if (pageInfo != null || loadRequest == null) {
2378            return pageInfo;
2379        }
2380
2381        EntryLoadRequest noLanguageLoadRequest
2382                = new EntryLoadRequest (loadRequest.getWorkflowState (),
2383                        loadRequest.getVersionID (), new ArrayList ());
2384        noLanguageLoadRequest.setWithDeleted (loadRequest.isWithDeleted ());
2385        noLanguageLoadRequest.setWithMarkedForDeletion (loadRequest.isWithMarkedForDeletion ());
2386
2387        noLanguageLoadRequest.getLocales ().add (new Locale (ContentField.SHARED_LANGUAGE, ""));
2388        pageInfo = getPageInfoVersion (noLanguageLoadRequest, isWrite, true);
2389        return pageInfo;
2390    }
2391
2392    /**
2393     * Returns the page info entry corresponding to the requested entry state.
2394     * Warning : this loads the versioning page infos if they were never loaded
2395     * and we are requesting a versioned entry state.
2396     *
2397     * @param entryState the entry state to find in the page info
2398     *
2399     * @return a JahiaPageInfo if we found the entry corresponding to the
2400     * entry state specified, or null if not found.
2401     *
2402     * @throws JahiaException raised if there was a problem loading the versioned
2403     * entries from the database.
2404     */

2405    protected JahiaPageInfo getPageInfo (ContentObjectEntryState entryState)
2406            throws JahiaException {
2407
2408        if (entryState == null) {
2409            return null;
2410        }
2411
2412        // first let's load the versioned entries if necessary.
2413
//if ( (mArchivedPageInfos.size() == 0) &&
2414
if ((mArchivedPageInfos == null) &&
2415                (entryState.getWorkflowState () <=
2416                ContentObjectEntryState.WORKFLOW_STATE_VERSIONED)) {
2417            Vector versionedPageInfos = JahiaPagesDB.getInstance ().
2418                    loadPageInfos (getID (),
2419                            EntryLoadRequest.VERSIONED);
2420            mPageInfos.addAll (versionedPageInfos);
2421            rebuildStatusMaps ();
2422        }
2423
2424        // now let's try to find the entry we are requesting.
2425
Iterator pageInfoIter = mPageInfos.iterator ();
2426        while (pageInfoIter.hasNext ()) {
2427            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
2428            if ((curPageInfo.getWorkflowState () == entryState.getWorkflowState ()) &&
2429                    (curPageInfo.getVersionID () == entryState.getVersionID ()) &&
2430                    (curPageInfo.getLanguageCode ().equals (entryState.getLanguageCode ()))) {
2431                return curPageInfo;
2432            }
2433        }
2434        return null;
2435    }
2436
2437    /**
2438     * This method just checks all the staged JahiaPageInfos and returns their
2439     * status
2440     *
2441     * @return an int containing the current staging status
2442     */

2443    private int getMostRecentStagingStatus () {
2444
2445        int currentStatus = EntryLoadRequest.STAGING_WORKFLOW_STATE;
2446
2447        // let's see the highest staging mode we are currently in
2448
// shouldn't all these be equal ?
2449
Iterator pageInfoIter = mPageInfos.iterator ();
2450        while (pageInfoIter.hasNext ()) {
2451            JahiaPageInfo thisPageInfo = (JahiaPageInfo) pageInfoIter.next ();
2452            if (thisPageInfo.getWorkflowState () >= EntryLoadRequest.STAGING_WORKFLOW_STATE)
2453                currentStatus = thisPageInfo.getWorkflowState ();
2454        }
2455        return currentStatus;
2456    }
2457
2458    /**
2459     * Shortcut method to the real getAllPageInfosForWrite that takes a set
2460     * of languages codes to create. See that method's description for more
2461     * details.
2462     *
2463     * @param jParams a ParamBean object used for two things. First to retrieve
2464     * the current request locale for which to make sure there is an entry in
2465     * the current version, and second to resolve the locale list in
2466     * the case we need to copy from other language versions. Basically the
2467     * ParamBean.getLocales() resolver is used in this method.
2468     *
2469     * @return a Vector of JahiaPageInfo objects that contain all the different
2470     * language versions for a given version (active or staging for the moment).
2471     *
2472     * @see getAllPageInfosForWrite(Set, ParamBean)
2473     */

2474    private Vector getAllPageInfosForWrite (EntryLoadRequest loadRequest)
2475            throws JahiaException {
2476        Set languageCodes = new HashSet ();
2477        String JavaDoc languageCode = null;
2478        if (loadRequest != null) {
2479            Locale firstLocale = loadRequest.getFirstLocale (true);
2480            if (firstLocale != null) {
2481                languageCode = firstLocale.toString ();
2482                languageCodes.add (languageCode);
2483            }
2484        }
2485        return getAllPageInfosForWrite (languageCodes);
2486    }
2487
2488    /**
2489     * This method returns all the PageInfos for a given version, basically
2490     * all the different existing languages PageInfos for a given version.
2491     * It also adds versions if it doesn't exist yet. This is very useful
2492     * when writing values that are shared among languages such as PageLinkID,
2493     * PageTemplateID, etc...
2494     *
2495     * @param languageCodes a set of String objects that represents the
2496     * languages for which we want to create values if they do not yet exist.
2497     *
2498     * @return a Vector of JahiaPageInfo objects that contain all the different
2499     * language versions for a given version (active or staging for the moment).
2500     */

2501    private Vector getAllPageInfosForWrite (Set languageCodes)
2502            throws JahiaException {
2503        Vector pageInfos = new Vector ();
2504
2505        // now we must insure that we create staging entries for ALL the
2506
// languages that exist in active mode, not only the ones we have
2507
// specified in our parameters. We also include the parameter languages
2508
// that will exist only in staging if they don't exist in active entries.
2509
Set writeLanguageCodes = new HashSet (languageCodes);
2510        writeLanguageCodes.addAll (mActivePageInfos.keySet ());
2511        writeLanguageCodes.removeAll (mStagingPageInfos.keySet ());
2512        writeLanguageCodes.addAll (languageCodes);
2513
2514        // now that the language set is fully determined, let's create the
2515
// necessary entries in staging.
2516
int currentStatus = getMostRecentStagingStatus ();
2517        Iterator languageCodeIter = writeLanguageCodes.iterator ();
2518        while (languageCodeIter.hasNext ()) {
2519            String JavaDoc curLanguageCode = (String JavaDoc) languageCodeIter.next ();
2520            boolean foundCurLanguage = false;
2521            // let's see if a currentInfo exist
2522

2523            if (mStagingPageInfos.containsKey (curLanguageCode)) {
2524                foundCurLanguage = true;
2525                JahiaPageInfo sourceActiveInfo = (JahiaPageInfo) mStagingPageInfos.get (
2526                        curLanguageCode);
2527                JahiaPageInfo newStagingInfo = sourceActiveInfo.clonePageInfo (sourceActiveInfo.getVersionID(),
2528                        sourceActiveInfo.getWorkflowState(), sourceActiveInfo.getLanguageCode ());
2529                mStagingPageInfos.put (curLanguageCode, newStagingInfo);
2530                if (mPageInfos.contains(newStagingInfo)) {
2531                  mPageInfos.remove(newStagingInfo);
2532                }
2533                mPageInfos.add (newStagingInfo);
2534            }
2535
2536            if (!foundCurLanguage) {
2537                // the current language doesn't exist in staging mode, does it
2538
// exist in active mode ?
2539
if (mActivePageInfos.containsKey (curLanguageCode)) {
2540                    // it does, let's copy from there
2541
JahiaPageInfo sourceActiveInfo = (JahiaPageInfo) mActivePageInfos.get (
2542                            curLanguageCode);
2543                    JahiaPageInfo newStagingInfo = sourceActiveInfo.clonePageInfo (0,
2544                            currentStatus, sourceActiveInfo.getLanguageCode ());
2545                    JahiaPagesDB.getInstance ().createPageInfo (newStagingInfo);
2546                    mStagingPageInfos.put (curLanguageCode, newStagingInfo);
2547                    mPageInfos.add (newStagingInfo);
2548                } else {
2549                    // it doesn't, let's create a copy from another language version
2550

2551                    JahiaPageInfo sourceInfo = null;
2552                    // first we must know if there are staging versions we can
2553
// copy the data from :
2554
if (mStagingPageInfos.size () == 0) {
2555                        // no staging page infos yet, we must copy from the active
2556
// versions
2557

2558                        /*
2559                        ArrayList locales = jParams.getEntryLoadRequest().getLocales();
2560                        ListIterator localesIter = locales.listIterator();
2561                        while (localesIter.hasNext()) {
2562                            Locale curLocale = (Locale) localesIter.next();
2563                            JahiaPageInfo curPageInfo = (JahiaPageInfo) mActivePageInfos.get(curLocale.toString());
2564                            if (curPageInfo != null) {
2565                                sourceInfo = curPageInfo;
2566                            }
2567                        }
2568                        */

2569
2570                        // NK : We just need to copy an entry no matter what language it is ?
2571
if (mActivePageInfos.size () > 0) {
2572                            sourceInfo =
2573                                    (JahiaPageInfo) mActivePageInfos.values ().iterator ().next ();
2574                        }
2575
2576                    } else {
2577
2578                        // there are staging page infos, let's determine which one
2579
// we must copy from.
2580
/*
2581                        ArrayList locales = jParams.getEntryLoadRequest().getLocales();
2582                        ListIterator localesIter = locales.listIterator();
2583                        while (localesIter.hasNext()) {
2584                            Locale curLocale = (Locale) localesIter.next();
2585                            JahiaPageInfo curPageInfo = (JahiaPageInfo) mStagingPageInfos.get(curLocale.toString());
2586                            if (curPageInfo != null) {
2587                                sourceInfo = curPageInfo;
2588                            }
2589                        }
2590                        */

2591
2592                        // NK : We just need to copy an entry no matter what language it is ?
2593
if (mStagingPageInfos.size () > 0) {
2594                            sourceInfo =
2595                                    (JahiaPageInfo) mStagingPageInfos.values ().iterator ().next ();
2596                        }
2597                    }
2598                    if (sourceInfo != null) {
2599                        JahiaPageInfo newStagingInfo = sourceInfo.clonePageInfo (0,
2600                                currentStatus, curLanguageCode);
2601                        newStagingInfo.setTitle (sourceInfo.getTitle ());
2602                        // NK : Setting the remote URL will change the page Type !
2603
// as we clone it no reason to set it.
2604
//newStagingInfo.setRemoteURL(sourceInfo.getRemoteURL());
2605
JahiaPagesDB.getInstance ().createPageInfo (newStagingInfo);
2606                        mStagingPageInfos.put (curLanguageCode, newStagingInfo);
2607                        mPageInfos.add (newStagingInfo);
2608                    } else {
2609                        logger.debug ("Couldn't create page (" + getID () +
2610                                ")content entry for language " +
2611                                curLanguageCode +
2612                                " because a source language couldn't be found.");
2613                    }
2614                }
2615            }
2616        }
2617
2618
2619        Iterator stagingValuesIter = mStagingPageInfos.values ().iterator ();
2620        while (stagingValuesIter.hasNext ()) {
2621            pageInfos.add (stagingValuesIter.next ());
2622        }
2623        return pageInfos;
2624    }
2625
2626    /**
2627     * Retrieves just one JahiaPageInfo for a writing operation. This is used
2628     * for non-shared language values such as the page title. It also creates
2629     * a language entry if it didn't exist previsouly.
2630     *
2631     * @param jParams a ParamBean object used to resolve both the version and
2632     * the language.
2633     *
2634     * @return a JahiaPageInfo corresponding to the desired language in staging
2635     * mode and ready for writing.
2636     *
2637     * @throws JahiaException thrown if we couldn't find or generate a language
2638     * for some reason.
2639     */

2640    private JahiaPageInfo getPageInfoVersionForWrite (EntryLoadRequest loadRequest)
2641            throws JahiaException {
2642
2643        getAllPageInfosForWrite (loadRequest);
2644        JahiaPageInfo resultInfo = (JahiaPageInfo) mStagingPageInfos.get (
2645                loadRequest.getFirstLocale (true).toString ());
2646        if (resultInfo == null) {
2647            throw new JahiaException ("ContentPage.getPageInfoForWrite",
2648                    "Couldn't find staging page data for language " +
2649                    loadRequest.getFirstLocale (true).toString (),
2650                    JahiaException.PAGE_ERROR,
2651                    JahiaException.ERROR_SEVERITY);
2652        }
2653
2654        return resultInfo;
2655
2656    }
2657
2658    /**
2659     * Removes an entry from the internal JahiaPageInfo vector. Please note that
2660     * this method is far from fast as it goes through the entire PageInfo list
2661     * and then reconstructs the internal maps by parsing the list once again !
2662     * But throughout this design we have been using a pattern of fast reads/
2663     * slow writes so it should be acceptable.
2664     *
2665     * @param pageInfo the JahiaPageInfo object to remove from the list.
2666     */

2667    private void removePageInfo (JahiaPageInfo pageInfo) {
2668        HashSet resultPageInfos = new HashSet ();
2669        Iterator pageInfoIter = mPageInfos.iterator ();
2670        while (pageInfoIter.hasNext ()) {
2671            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
2672            if (!curPageInfo.equals (pageInfo)) {
2673                resultPageInfos.add (curPageInfo);
2674            }
2675        }
2676        mPageInfos = resultPageInfos;
2677        rebuildStatusMaps ();
2678    }
2679
2680    /**
2681     * The purpose of this method is to "activate" all the data that is in the
2682     * staging state. This destroys all internal staging entries so make sure
2683     * you call this only when really ready to active. For changing staging
2684     * status use the other method : changeStagingStatus also in this class.
2685     *
2686     * @param languageCodes specifies for which languages to activate. All the
2687     * languages that are not specified here will not change state
2688     * @param versioningActive specifies whether the versioning system is
2689     * active on this site
2690     * @param saveVersion version save information passed to all the content
2691     * of the page for activation.
2692     * @param user the user making the validation, using for validation the
2693     * content of the page
2694     * @param jParams a ParamBean object used in sub-object (todo : find exactly
2695     * what it is used for !)
2696     * @param stateModifContext contains the current context of the activation,
2697     * including the current tree path stack and options that indicate how
2698     * the activation should be processed such as whether to recursively descend
2699     * in sub pages.
2700     *
2701     * @return true if the page was successfully validated, false if it could
2702     * not be validated due to it's dependency on another page or content that
2703     * links to other pages.
2704     *
2705     * @throws JahiaException if there was a problem while validating the
2706     * content of the page.
2707     */

2708    public ActivationTestResults activeStagingEntries (
2709            Set languageCodes,
2710            boolean versioningActive,
2711            JahiaSaveVersion saveVersion,
2712            JahiaUser user,
2713            ParamBean jParams,
2714            StateModificationContext stateModifContext)
2715            throws JahiaException {
2716
2717        boolean stateModified = false;
2718        if (willBeCompletelyDeleted (null, languageCodes)) {
2719            stateModified = true;
2720            stateModifContext.pushAllLanguages (true);
2721            this.removeProperty(PageProperty.PAGE_URL_KEY_PROPNAME);
2722        }
2723
2724        Set activateLanguageCodes = new HashSet (languageCodes);
2725        if (stateModifContext.isAllLanguages ()) {
2726            activateLanguageCodes.addAll (getStagingLanguages (true));
2727        }
2728
2729        ActivationTestResults activationResults = new ActivationTestResults ();
2730
2731        activationResults.merge (
2732                isValidForActivation (activateLanguageCodes, versioningActive, saveVersion,
2733                        user, jParams, stateModifContext));
2734        if (activationResults.getStatus () == ActivationTestResults.FAILED_OPERATION_STATUS) {
2735            if (stateModified) {
2736                stateModifContext.popAllLanguages ();
2737            }
2738            return activationResults;
2739        }
2740
2741        ContentPageKey pageKey = new ContentPageKey (getID ());
2742        boolean stacked = false;
2743
2744        // the first operation is to check if we validate the object or not,
2745
// depending on whether the objects pointed by this one are validated
2746
// or not. In the case of internal links we must check that the
2747
// page link has been validated or not, and depending on the parameters,
2748
// whether to validate it first too.
2749
int pageType = -1;
2750
2751        // FIXME NK : we should get the staged entry first should we ?
2752
// Iterator pageInfoIter = mPageInfos.iterator();
2753
Iterator pageInfoIter = mStagingPageInfos.values ().iterator ();
2754        if (!pageInfoIter.hasNext ()) {
2755            pageInfoIter = this.mActivePageInfos.values ().iterator ();
2756        }
2757
2758        if (pageInfoIter.hasNext ()) {
2759            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
2760            pageType = curPageInfo.getPageType ();
2761            if (pageType == JahiaPage.TYPE_LINK) {
2762                logger.debug ("Activating link page object (id=" +
2763                        curPageInfo.getID () + ") to page ID : " +
2764                        curPageInfo.getPageLinkID ());
2765            } else if (pageType == JahiaPage.TYPE_DIRECT) {
2766                if (!stateModifContext.isDescendingInSubPages () &&
2767                        !stateModifContext.getStartObject ().equals (pageKey)) {
2768                    // found a recursive call, let's abort now !
2769
logger.debug ("Activation stopped here " + pageKey.toString () +
2770                            " because recursive activation is not activated ! ");
2771                    activationResults.setStatus (ActivationTestResults.FAILED_OPERATION_STATUS);
2772                    activationResults.appendError (
2773                            "Activation stopped here " + pageKey.toString () +
2774                            " because recursive activation is not activated ! ");
2775                    if (stateModified) {
2776                        stateModifContext.popAllLanguages ();
2777                    }
2778                    return activationResults;
2779                }
2780                stateModifContext.pushObjectID (new ContentPageKey (getID ()));
2781                stacked = true;
2782                logger.debug ("Current stateModifContext :" + stateModifContext.toString ());
2783
2784                ServicesRegistry sr = ServicesRegistry.getInstance ();
2785                activationResults.merge (
2786                        sr.getJahiaFieldService ().activateStagedFields (languageCodes,
2787                                getID (), user, saveVersion, jParams, stateModifContext));
2788                activationResults.merge (
2789                        sr.getJahiaContainersService ().activateStagedContainers (
2790                                languageCodes, getID (), user, saveVersion, jParams,
2791                                stateModifContext));
2792                activationResults.merge (
2793                        sr.getJahiaContainersService ().activateStagedContainerLists (
2794                                languageCodes, getID (), user, saveVersion, stateModifContext));
2795
2796                // we should activate all staged pages links in requested languages too
2797
/** @todo FIXME here we really shouldn't migrate these to
2798                 * warnings because they do represent data corruption problems.
2799                 */

2800                ActivationTestResults linkActivationResults = this.activeStagedLinkPages(languageCodes,versioningActive,
2801                    saveVersion,user,jParams);
2802                if (linkActivationResults.getStatus() == ActivationTestResults.FAILED_OPERATION_STATUS) {
2803                    linkActivationResults.setStatus(ActivationTestResults.PARTIAL_OPERATION_STATUS);
2804                    linkActivationResults.moveErrorsToWarnings();
2805                }
2806                activationResults.merge (linkActivationResults);
2807
2808            }
2809        }
2810
2811        // Invalidate the JahiaPageCacheInfo
2812
this.commitChanges (true);
2813        rebuildStatusMaps ();
2814
2815        int sameParentID = hasSameParentID ();
2816        if (!stateModifContext.isAllLanguages () && (sameParentID != SAME_PARENT)) {
2817            logger.debug (
2818                    "Activation of move detected for page " + getID () + ", activating all languages...");
2819            activateLanguageCodes.addAll (getStagingLanguages (true));
2820        }
2821
2822
2823        activeNonDeletedEntries (activateLanguageCodes, saveVersion);
2824
2825        // if the activation was at least partially performed, we must now
2826
// also activate all the content that points on this page.
2827

2828        activeReferringContent (languageCodes, saveVersion, user,
2829                jParams, stateModifContext, activationResults);
2830
2831        activeDeletedEntries (activateLanguageCodes, saveVersion);
2832
2833        if (stacked) {
2834            stateModifContext.popObjectID ();
2835        }
2836
2837        if (stateModified) {
2838            stateModifContext.popAllLanguages ();
2839        }
2840
2841
2842        // Invalidate the JahiaPageCacheInfo
2843
// @todo : create a singleton for all pageInfo !!
2844
this.commitChanges (true);
2845
2846        fireContentActivationEvent(languageCodes,
2847                                   versioningActive,
2848                                   saveVersion,
2849                                   jParams,
2850                                   stateModifContext,
2851                                   activationResults);
2852
2853        return activationResults;
2854
2855    }
2856
2857    private void activeNonDeletedEntries (Set languageCodes,
2858                                          JahiaSaveVersion saveVersion) throws JahiaException {
2859        // now we must find which active versions to backup, by figuring
2860
// out what has changed. Here we only do the activation parts. The
2861
// deletion parts will be done later, because they must be done
2862
// in the end since we might have no references left to page info
2863
// objects after deletion.
2864
Iterator stagingIter = mStagingPageInfos.values ().iterator ();
2865        while (stagingIter.hasNext ()) {
2866            JahiaPageInfo curPageInfo = (JahiaPageInfo) stagingIter.next ();
2867
2868            // only do the activation for the request languages.
2869
if (languageCodes.contains (curPageInfo.getLanguageCode ())) {
2870                int newVersionStatus = 0;
2871                if (curPageInfo.getVersionID () != -1) {
2872                    try {
2873
2874                        // now le'ts find the active page info corresponding to this
2875
// staged page info.
2876
JahiaPageInfo activeInfo = (JahiaPageInfo)
2877                                mActivePageInfos.get (curPageInfo.getLanguageCode ());
2878
2879                        if (activeInfo != null) {
2880
2881                            // create a versioned version of the old active entry
2882
JahiaPagesDB.getInstance ().backupPageInfo (
2883                                    activeInfo,
2884                                    activeInfo.getVersionID (),
2885                                    newVersionStatus);
2886
2887                            // now we delete the active info since we are either replacing
2888
// it with a staging version of removing it definitely
2889
JahiaPagesDB.getInstance ().deletePageInfo (
2890                                    activeInfo);
2891                            removePageInfo (activeInfo);
2892                            mActivePageInfos.remove(activeInfo.getLanguageCode());
2893
2894                        }
2895
2896                        removePageInfo (curPageInfo);
2897
2898                        /*
2899                        // before we activate a staged entry, we must be sure to remove
2900                        // to remove any versioning entry with same saveVersion Id
2901                        JahiaPageInfo versioningPageInfo =
2902                            curPageInfo.clonePageInfo(saveVersion.getVersionID (),
2903                                                      EntryLoadRequest.VERSIONED_WORKFLOW_STATE,
2904                                                      curPageInfo.getLanguageCode());
2905
2906                        JahiaPagesDB.getInstance ().deletePageInfo(
2907                                versioningPageInfo);
2908                        removePageInfo (versioningPageInfo);
2909                        */

2910
2911                        // not marked for deletion, let's activate it.
2912
JahiaPagesDB.getInstance ().updatePageInfo (
2913                                curPageInfo,
2914                                saveVersion.getVersionID (),
2915                                EntryLoadRequest.ACTIVE_WORKFLOW_STATE);
2916
2917                        curPageInfo.setVersionID (saveVersion.getVersionID ());
2918                        curPageInfo.setVersionStatus (EntryLoadRequest.
2919                                ACTIVE_WORKFLOW_STATE);
2920
2921                        mPageInfos.add (curPageInfo);
2922                        mActivePageInfos.put (curPageInfo.getLanguageCode (),
2923                                curPageInfo);
2924                    } catch (JahiaException je) {
2925                        // PAP: this is a serious error and should not happen, we
2926
// should not just swallow and continue but should rollback.
2927
logger.error (
2928                                "Error while trying to activate staging version",
2929                                je);
2930                        throw je;
2931                    }
2932                }
2933            }
2934        }
2935    }
2936
2937
2938    private void activeReferringContent (Set languageCodes,
2939                                         JahiaSaveVersion saveVersion,
2940                                         JahiaUser user, ParamBean jParams,
2941                                         StateModificationContext
2942            stateModifContext,
2943                                         ActivationTestResults activationResults)
2944            throws JahiaException {
2945        /**
2946         * @todo we might be missing code to handle the "activation" of
2947         * deleted pages AND the content pointing on this page (ie broken
2948         * links that have to be navigated up to destroy the content)
2949         */

2950
2951        if (activationResults.getStatus () !=
2952                ActivationTestResults.FAILED_OPERATION_STATUS
2953                && (this.getPageType (jParams.getEntryLoadRequest ()) != JahiaPage.TYPE_URL)
2954                && (this.getPageType (jParams.getEntryLoadRequest ()) != JahiaPage.TYPE_LINK)) {
2955            // now that we've activate the page entry, let's activate all the
2956
// related content on other pages.
2957

2958            Vector referingPages = ServicesRegistry.getInstance ().
2959                    getJahiaPageService ().
2960                    getPagesPointingOnPage (getID (), jParams);
2961
2962            // let's add our own page, only if we are at the start.
2963
if (stateModifContext.getStartObject ().equals (new ContentPageKey (getID ()))) {
2964                referingPages.add (new JahiaPage (this, getPageTemplate (jParams),
2965                        getACL (),
2966                        jParams.getEntryLoadRequest ()));
2967            }
2968
2969            Enumeration referingPagesEnum = referingPages.elements ();
2970            while (referingPagesEnum.hasMoreElements ()) {
2971                JahiaPage curPage = (JahiaPage) referingPagesEnum.nextElement ();
2972
2973                Vector curPointingPageFieldIDs = JahiaPageUtilsDB.getInstance()
2974                    .getStagingAndActivePageFieldIDs(curPage.getID());
2975
2976                Iterator fieldIDsIter = curPointingPageFieldIDs.iterator ();
2977                while (fieldIDsIter.hasNext ()) {
2978                    int curFieldID = ((Integer JavaDoc) fieldIDsIter.next ()).intValue ();
2979                    if (curFieldID != -1) {
2980                        ContentField curPageField = ContentField.getField (
2981                                curFieldID);
2982                        if (curPageField == null) {
2983                            logger.debug ("Couldn't find page field " +
2984                                    curFieldID +
2985                                    " pointing on page " + getID () +
2986                                    ", ignoring it...");
2987                        } else {
2988
2989                            boolean notDeleted = (curPageField.hasActiveEntries ()
2990                                    ||
2991                                    curPageField.hasStagingEntries ());
2992
2993                            // we must now activate the field.
2994
stateModifContext.setDescendingInSubPages (false);
2995                            boolean pageFieldActivationResult = true;
2996                            if (curPageField.hasStagingEntries ()) {
2997                                // fire event
2998
JahiaEvent theEvent = new JahiaEvent(
2999                                        saveVersion, jParams, curPageField);
3000                                ServicesRegistry.getInstance()
3001                                        .getJahiaEventService()
3002                                        .fireBeforeFieldActivation(theEvent);
3003                                // end fire event
3004
ActivationTestResults fieldActivationResult =
3005                                        curPageField.activate (
3006                                                languageCodes,
3007                                                saveVersion.getVersionID (),
3008                                                jParams,
3009                                                stateModifContext);
3010                                activationResults.merge (fieldActivationResult);
3011                                pageFieldActivationResult = (fieldActivationResult.getStatus () ==
3012                                        ActivationTestResults.COMPLETED_OPERATION_STATUS);
3013
3014                            }
3015                            if (pageFieldActivationResult) {
3016
3017                                if ((curPageField.getContainerID () > 0) &&
3018                                        notDeleted) {
3019                                    // field is inside a container.
3020
/**
3021                                     * @todo we might want to check this code
3022                                     * to make sure we load the correct entry
3023                                     * state here
3024                                     */

3025                                    JahiaContainer curPageFieldContainer =
3026                                            ServicesRegistry.getInstance ().
3027                                            getJahiaContainersService ().
3028                                            loadContainer (
3029                                                    curPageField.getContainerID (),
3030                                                    LoadFlags.ALL, jParams,
3031                                                    jParams.getEntryLoadRequest ());
3032                                    if (curPageFieldContainer == null) {
3033                                        logger.debug (
3034                                                "Error loading container (" +
3035                                                curPageField.getContainerID () +
3036                                                ") for a page field (" +
3037                                                curFieldID +
3038                                                ") that points on page " + getID ());
3039                                    } else {
3040                                        // container was successfully loaded.
3041
// we must now try to activate it.
3042
stateModifContext.
3043                                                setDescendingInSubPages (false);
3044
3045                                        // we must now activate all the other
3046
// field in the container first, and
3047
// then validate the container itself.
3048
EntryLoadRequest loadRequest = new EntryLoadRequest (
3049                                                EntryLoadRequest.STAGED);
3050                                        loadRequest.setWithMarkedForDeletion (true);
3051
3052                                        Vector fieldIDs = ServicesRegistry.
3053                                                getInstance ().
3054                                                getJahiaContainersService ().
3055                                                getFieldIDsInContainer (
3056                                                        curPageFieldContainer.getID (),
3057                                                        loadRequest);
3058
3059                                        for (int j = 0; j < fieldIDs.size (); j++) {
3060                                            int fieldID = ((Integer JavaDoc) fieldIDs.elementAt (j)).intValue ();
3061                                            if (fieldID != curFieldID) {
3062                                                ContentField currentField =
3063                                                        ContentField.getField (
3064                                                                fieldID);
3065
3066                                                // fire event
3067
JahiaEvent theEvent = new JahiaEvent (
3068                                                        saveVersion, jParams, currentField);
3069                                                ServicesRegistry.getInstance ()
3070                                                        .getJahiaEventService ()
3071                                                        .fireBeforeFieldActivation (theEvent);
3072
3073                                                activationResults.merge (
3074                                                        currentField.activate (
3075                                                                languageCodes,
3076                                                                saveVersion.getVersionID(), jParams,
3077                                                                stateModifContext));
3078                                            }
3079                                        }
3080
3081                                        // now that we have activated, or at
3082
// least tried to activate all the
3083
// fields, we must activate the
3084
// container itself.
3085

3086                                        ActivationTestResults
3087                                                containerActivationResult =
3088                                                ServicesRegistry.getInstance ().
3089                                                getJahiaContainersService ().
3090                                                activateStagedContainer (
3091                                                        languageCodes,
3092                                                        curPageFieldContainer.getID (),
3093                                                        user, saveVersion, jParams,
3094                                                        stateModifContext);
3095                                        activationResults.merge (
3096                                                containerActivationResult);
3097
3098                                        // It's important to active the parent container list too
3099
// to have correct versioning state
3100
try {
3101                                            ContentContainerList containerList =
3102                                                ContentContainerList.
3103                                                getContainerList(
3104                                                curPageFieldContainer.getListID());
3105                                            if ( containerList != null ){
3106                                                 containerActivationResult = ServicesRegistry.getInstance().getJahiaContainersService()
3107                                                    .activateStagedContainerLists(languageCodes,
3108                                                                                  getID(),
3109                                                                                  user,
3110                                                                                  saveVersion,
3111                                                                                  stateModifContext);
3112                                                  activationResults.merge(
3113                                                      containerActivationResult);
3114                                            }
3115                                        } catch ( Throwable JavaDoc t ){
3116                                            logger.error("Error activating container list ",t);
3117                                            throw new JahiaException(
3118                                                    "Error in workflow, container list on page can not be activated",
3119                                                    "Error activating container list ", JahiaException.OBJECT_ERROR,
3120                                                    JahiaException.ERROR_SEVERITY, t);
3121                                        }
3122                                    }
3123                                } else {
3124                                    // field is not in a container. nothing more to do...
3125
}
3126                            }
3127                        }
3128                    }
3129                }
3130            }
3131        }
3132    }
3133
3134    private void activeDeletedEntries (Set languageCodes,
3135                                       JahiaSaveVersion saveVersion) throws JahiaException {
3136        // now we must find which active versions to backup, by figuring
3137
// out what has changed.
3138
Iterator stagingDeleteIter = mStagingPageInfos.values ().iterator ();
3139        while (stagingDeleteIter.hasNext ()) {
3140            JahiaPageInfo curPageInfo = (JahiaPageInfo) stagingDeleteIter.next ();
3141
3142            // only do the activation for the request languages.
3143
if (languageCodes.contains (curPageInfo.getLanguageCode ())) {
3144                if (curPageInfo.getVersionID () == -1) {
3145                    // page info is marked to be deleted, the backup status will
3146
// be -1
3147
try {
3148
3149                        // now le'ts find the active page info corresponding to this
3150
// staged page info.
3151
JahiaPageInfo activeInfo = (JahiaPageInfo)
3152                                mActivePageInfos.get (curPageInfo.getLanguageCode ());
3153
3154                        if (activeInfo != null) {
3155
3156                            // create a versioned version of the old active entry
3157

3158                            // First, we create an archive entry ( newVersionStatus = 0 , not -1 ! )
3159
JahiaPagesDB.getInstance ().backupPageInfo (
3160                                    activeInfo,
3161                                    activeInfo.getVersionID (),
3162                                    ContentObjectEntryState.WORKFLOW_STATE_VERSIONED);
3163
3164                            // Second, we delete the active info since we are either replacing
3165
// it with a staging version of removing it definitely
3166
JahiaPagesDB.getInstance ().deletePageInfo (
3167                                    activeInfo);
3168                            removePageInfo (activeInfo);
3169                            mActivePageInfos.remove (activeInfo.getLanguageCode ());
3170
3171                            // Third, we replace the active with the staging entry
3172
JahiaPagesDB.getInstance ()
3173                                    .updatePageInfo (curPageInfo,
3174                                            saveVersion.getVersionID (),
3175                                            ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED);
3176
3177                            JahiaPageInfo deletedPageInfo =
3178                                    curPageInfo.clonePageInfo (saveVersion.getVersionID (),
3179                                            ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED,
3180                                            curPageInfo.getLanguageCode ());
3181
3182                            // ensure to load all versioning entryStates
3183
this.loadVersioningEntryStates ();
3184
3185                            this.mPageInfos.add (deletedPageInfo);
3186                            this.mArchivedPageInfos.add (deletedPageInfo);
3187
3188                            // reset site map
3189
ServicesRegistry.getInstance ().getJahiaSiteMapService ()
3190                                    .resetSiteMap ();
3191
3192                        }
3193
3194                        removePageInfo (curPageInfo);
3195                        // marked for deletion, let's remove the staged version
3196
// too...
3197
JahiaPagesDB.getInstance ().deletePageInfo (curPageInfo);
3198                    } catch (JahiaException je) {
3199                        logger.error (
3200                                "Error while trying to activate staging version",
3201                                je);
3202                        throw je;
3203                    }
3204                }
3205            }
3206        }
3207    }
3208
3209
3210    /**
3211     * Tests if a page is valid for activation.
3212     *
3213     * @param languageCodes a Set of languages for which to test if the page
3214     * is valid for activation.
3215     * @param versioningActive
3216     * @param saveVersion
3217     * @param user
3218     * @param jParams
3219     * @param stateModifContext contains the current context of the activation,
3220     * including the current tree path stack and options that indicate how
3221     * the activation should be processed such as whether to recursively descend
3222     * in sub pages.
3223     *
3224     * @return an ActivationTestResults object that contains the status of
3225     * the activation tests, including error and warning messages.
3226     *
3227     * @throws JahiaException
3228     */

3229    public ActivationTestResults isValidForActivation (
3230            Set languageCodes,
3231            boolean versioningActive,
3232            JahiaSaveVersion saveVersion,
3233            JahiaUser user,
3234            ParamBean jParams,
3235            StateModificationContext stateModifContext)
3236            throws JahiaException {
3237        ActivationTestResults activationTestResults = new ActivationTestResults ();
3238        int pageType = getPageType (EntryLoadRequest.STAGED);
3239
3240        // first we must test if we have all the mandatory languages in our
3241
// page only if the page is not marked for deletion.
3242
if (!isMarkedForDelete()) {
3243            JahiaSite theSite = jParams.getSite();
3244            Vector languageSettings = theSite.getLanguageSettings();
3245            Enumeration languageSettingsEnum = languageSettings.elements();
3246            while (languageSettingsEnum.hasMoreElements()) {
3247                SiteLanguageSettings curSettings = (SiteLanguageSettings)
3248                                                   languageSettingsEnum.nextElement();
3249                if (curSettings.isMandatory() && curSettings.isActivated()) {
3250                    // we found a mandatory language, let's check that there at
3251
// least an active or a staged entry for this field.
3252
JahiaPageInfo foundPageInfo = (JahiaPageInfo) mStagingPageInfos.get(
3253                        curSettings.getCode());
3254                    if (foundPageInfo == null) {
3255                        foundPageInfo = (JahiaPageInfo) mActivePageInfos.get(
3256                            curSettings.getCode());
3257                    }
3258
3259                    if (foundPageInfo == null) {
3260                        activationTestResults.setStatus(
3261                            ActivationTestResults.FAILED_OPERATION_STATUS);
3262                        try {
3263                            final EngineMessage msg = new EngineMessage(
3264                                    "org.jahia.services.pages.ContentPage.mandatoryLangMissingError");
3265                            IsValidForActivationResults activationResults = new
3266                                IsValidForActivationResults(
3267                                    ContentPageKey.PAGE_TYPE, getID(),
3268                                    curSettings.getCode(), msg);
3269                            activationTestResults.appendError(activationResults);
3270                        } catch (ClassNotFoundException JavaDoc cnfe) {
3271                            logger.debug(
3272                                "Error while creating activation test node result",
3273                                cnfe);
3274                        }
3275                        return activationTestResults;
3276                    }
3277
3278                }
3279            }
3280        }
3281
3282        // let's check that all the page titles exist in the languages to be
3283
// validated.
3284
Iterator languageCodeIter = languageCodes.iterator ();
3285        while (languageCodeIter.hasNext ()) {
3286            String JavaDoc curLanguageCode = (String JavaDoc) languageCodeIter.next ();
3287            JahiaPageInfo curPageInfo = (JahiaPageInfo) mStagingPageInfos.get (curLanguageCode);
3288            if (curPageInfo == null) {
3289                // no staging page info found, let's try in active...
3290
curPageInfo = (JahiaPageInfo) mActivePageInfos.get (curLanguageCode);
3291                if (curPageInfo == null) {
3292                    try {
3293                        final EngineMessage msg = new EngineMessage(
3294                                "org.jahia.services.pages.ContentPage.noTitleError");
3295                        activationTestResults.appendError (
3296                                new IsValidForActivationResults (
3297                                        ContentPageKey.PAGE_TYPE, getID (),
3298                                        curLanguageCode, msg));
3299                    } catch (ClassNotFoundException JavaDoc cnfe) {
3300                        logger.debug (
3301                                "Error while creating activation test node result",
3302                                cnfe);
3303                    }
3304                } else {
3305                    // we found a page info, let's check if the title was set.
3306
// normally this should always be the case if the page
3307
// was activated !!! If this is false it means the database
3308
// is corrupted !
3309
if (curPageInfo.getTitle () == null) {
3310                        // missing title, let's signal it.
3311
activationTestResults.setStatus (ActivationTestResults.
3312                                FAILED_OPERATION_STATUS);
3313                        try {
3314                            final EngineMessage msg = new EngineMessage(
3315                                    "org.jahia.services.pages.ContentPage.noTitleError");
3316                            activationTestResults.appendError (
3317                                    new IsValidForActivationResults (ContentPageKey.PAGE_TYPE,
3318                                            getID (),
3319                                            curPageInfo.getLanguageCode (), msg));
3320                        } catch (ClassNotFoundException JavaDoc cnfe) {
3321                            logger.debug ("Error while creating activation test node result",
3322                                    cnfe);
3323                        }
3324                    } else if ("".equals (curPageInfo.getTitle ().trim ())) {
3325                        // empty title, let's signal it
3326
activationTestResults.setStatus (ActivationTestResults.
3327                                FAILED_OPERATION_STATUS);
3328                        try {
3329                            final EngineMessage msg = new EngineMessage(
3330                                    "org.jahia.services.pages.ContentPage.emptyTitleError");
3331                            activationTestResults.appendError (
3332                                    new IsValidForActivationResults (ContentPageKey.PAGE_TYPE,
3333                                            getID (),
3334                                            curPageInfo.getLanguageCode (), msg));
3335                        } catch (ClassNotFoundException JavaDoc cnfe) {
3336                            logger.debug ("Error while creating activation test node result",
3337                                    cnfe);
3338                        }
3339                    }
3340                }
3341            } else {
3342                // let's check if the title was set.
3343
if (curPageInfo.getTitle () == null) {
3344                    // missing title, let's signal it.
3345
activationTestResults.setStatus (ActivationTestResults.
3346                            FAILED_OPERATION_STATUS);
3347                    try {
3348                        final EngineMessage msg = new EngineMessage(
3349                                "org.jahia.services.pages.ContentPage.noTitleError");
3350                        activationTestResults.appendError (
3351                                new IsValidForActivationResults (ContentPageKey.PAGE_TYPE,
3352                                        getID (),
3353                                        curPageInfo.getLanguageCode (), msg));
3354                    } catch (ClassNotFoundException JavaDoc cnfe) {
3355                        logger.debug ("Error while creating activation test node result", cnfe);
3356                    }
3357                } else if ("".equals (curPageInfo.getTitle ().trim ())) {
3358                    // empty title, let's signal it
3359
activationTestResults.setStatus (ActivationTestResults.
3360                            FAILED_OPERATION_STATUS);
3361                    try {
3362                        final EngineMessage msg = new EngineMessage(
3363                                "org.jahia.services.pages.ContentPage.emptyTitleError");
3364                        activationTestResults.appendError (
3365                                new IsValidForActivationResults (ContentPageKey.PAGE_TYPE,
3366                                        getID (),
3367                                        curPageInfo.getLanguageCode (), msg));
3368                    } catch (ClassNotFoundException JavaDoc cnfe) {
3369                        logger.debug ("Error while creating activation test node result", cnfe);
3370                    }
3371                }
3372            }
3373        }
3374
3375        // the next operation is to check if we validate the object or not,
3376
// depending on whether the objects pointed by this one are validated
3377
// or not. In the case of internal links we must check that the
3378
// page link has been validated or not, and depending on the parameters,
3379
// whether to validate it first too.
3380
pageType = -1;
3381        Iterator pageInfoIter = mPageInfos.iterator ();
3382        if (pageInfoIter.hasNext ()) {
3383            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
3384            pageType = curPageInfo.getPageType ();
3385            if (pageType == JahiaPage.TYPE_LINK) {
3386                ContentPage linkedPage = null;
3387                try {
3388                    ServicesRegistry.getInstance().getJahiaPageService()
3389                        .lookupContentPage(curPageInfo.getPageLinkID(), true);
3390                } catch (JahiaPageNotFoundException jpnfe) {
3391                    linkedPage = null;
3392                    try {
3393                        final EngineMessage msg = new EngineMessage(
3394                                "org.jahia.services.pages.ContentPage.linkNotToPageWarning");
3395                        activationTestResults.appendWarning(new
3396                            IsValidForActivationResults(ContentPageKey.
3397                            PAGE_TYPE,
3398                            getID(),
3399                            curPageInfo.getLanguageCode(), msg));
3400                    } catch (ClassNotFoundException JavaDoc cnfe) {
3401                        logger.debug ("Error while creating activation test node result",
3402                                      cnfe);
3403                    }
3404                }
3405                if (linkedPage != null) {
3406                    if (!linkedPage.hasActiveEntries ()) {
3407                        logger.debug (
3408                                "Cannot validate page link " + curPageInfo.getID () + "since it links to a page (" + curPageInfo.getPageLinkID () + ") with no active entries");
3409                        activationTestResults.setStatus (ActivationTestResults.
3410                                FAILED_OPERATION_STATUS);
3411                        try {
3412                            final EngineMessage msg = new EngineMessage(
3413                                    "org.jahia.services.pages.ContentPage.linkNotToActivePageError");
3414                            activationTestResults.appendError (
3415                                    new IsValidForActivationResults (ContentPageKey.PAGE_TYPE,
3416                                            getID (),
3417                                            curPageInfo.getLanguageCode (), msg));
3418                        } catch (ClassNotFoundException JavaDoc cnfe) {
3419                            logger.debug ("Error while creating activation test node result",
3420                                    cnfe);
3421                        }
3422                    }
3423                }
3424            } else if (pageType == JahiaPage.TYPE_DIRECT) {
3425                ServicesRegistry sr = ServicesRegistry.getInstance ();
3426                // we should modify this call to make it only test the fields that are directly attached to the page, and not in containers, otherwise we will
3427
// get doubles when testing the containers.
3428
// activationTestResults.merge(sr.getJahiaFieldService().areFieldsValidForActivation( languageCodes, getID(), user, saveVersion, jParams, withSubPages ));
3429
activationTestResults.merge (
3430                        sr.getJahiaFieldService ().areNonContainerFieldsValidForActivation (
3431                              languageCodes, getID (), user, saveVersion, jParams,
3432                              stateModifContext));
3433                activationTestResults.merge (
3434                        sr.getJahiaContainersService ().areContainersValidForActivation (
3435                                languageCodes, getID (), user, saveVersion, jParams,
3436                                stateModifContext));
3437                activationTestResults.merge (
3438                        sr.getJahiaContainersService ().areContainerListsValidForActivation (
3439                                languageCodes, getID (), user, saveVersion, stateModifContext));
3440            }
3441        }
3442
3443        return activationTestResults;
3444    }
3445
3446    /**
3447     * Changes the status of the staging page infos. This is used to switch
3448     * to another status, before going to active status. No versioning is
3449     * done during a staging status change.
3450     *
3451     * @param languageCodes a set of language codes for which we want to
3452     * change the state. Other languages will not change state.
3453     * @param newWorkflowState the new status mode. This must be bigger or
3454     * equal to JahiaLoadVersion.STAGING, otherwise this method will exist
3455     * immediately.
3456     * @param jParams a ParamBean used in sub content during the changing
3457     * state (todo : find exactly what it is used for)
3458     * @param withSubPages specifies whether to descend into sub pages to also
3459     * modify their state
3460     *
3461     * @throws JahiaException in the case there are problems interacting with
3462     * the persistant store while changing the state
3463     */

3464    public void changeStagingStatus (Set languageCodes, int newWorkflowState,
3465                                     ParamBean jParams,
3466                                     StateModificationContext stateModifContext)
3467            throws JahiaException {
3468        if (newWorkflowState < EntryLoadRequest.STAGING_WORKFLOW_STATE) {
3469            return;
3470        }
3471
3472        // the first operation to do is to change the status of all the fields
3473
// in the page.
3474
int pageType = -1;
3475        Iterator pageInfoIter = mPageInfos.iterator ();
3476        if (pageInfoIter.hasNext ()) {
3477            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
3478            pageType = curPageInfo.getPageType ();
3479            if (pageType == JahiaPage.TYPE_LINK) {
3480
3481            } else if (pageType == JahiaPage.TYPE_DIRECT) {
3482                ServicesRegistry sr = ServicesRegistry.getInstance ();
3483                sr.getJahiaFieldService ().setFieldsLanguageStates (languageCodes,
3484                        newWorkflowState, getID (), jParams, stateModifContext);
3485            }
3486        }
3487
3488        Set processedLangs = new HashSet ();
3489        Iterator stagingIter = mStagingPageInfos.values ().iterator ();
3490        try {
3491            while (stagingIter.hasNext ()) {
3492                JahiaPageInfo curPageInfo = (JahiaPageInfo) stagingIter.next ();
3493                if (languageCodes.contains (curPageInfo.getLanguageCode ())) {
3494                    processedLangs.add (curPageInfo.getLanguageCode ());
3495                    JahiaPagesDB.getInstance ().updatePageInfo (curPageInfo,
3496                            curPageInfo.getVersionID (), newWorkflowState);
3497                    curPageInfo.setVersionStatus (newWorkflowState);
3498                }
3499            }
3500
3501            // we create an entry for missing language
3502
stagingIter = languageCodes.iterator ();
3503            while (stagingIter.hasNext ()) {
3504                String JavaDoc lang = (String JavaDoc) stagingIter.next ();
3505                if (!processedLangs.contains (lang)) {
3506                    // the staging does'nt exist in the given language, so
3507
// we directly create one entry in the new workflow state
3508
Iterator iterator = this.getActiveAndStagingEntryStates ().iterator ();
3509                    while (iterator.hasNext ()) {
3510                        ContentObjectEntryState fromEntryState =
3511                                (ContentObjectEntryState) iterator.next ();
3512                        if (fromEntryState.getLanguageCode ().equals (lang)) {
3513                            ContentObjectEntryState toEntryState =
3514                                    new ContentObjectEntryState (newWorkflowState, 0, lang);
3515                            this.copyEntry (fromEntryState, toEntryState);
3516                        }
3517                    }
3518                }
3519            }
3520        } catch (JahiaException je) {
3521            logger.debug ("Error while trying to change the status of a staging version", je);
3522        }
3523
3524        // Invalidate the JahiaPageCacheInfo
3525
this.commitChanges (true);
3526        rebuildStatusMaps ();
3527
3528    }
3529
3530    /**
3531     * Marks a page's languages content for deletion.
3532     * Does not delete the languages entries until the page is published.
3533     * This method also goes done in the content to flag all the content
3534     * for deletion along with the page in the given set of languages.
3535     *
3536     * @param user the user performing the operation, in order to perform
3537     * rights checks
3538     * @param languageCode the language to mark for deletion
3539     * @param stateModificationContext contains the start object of the
3540     * operation, as well as settings such as recursive descending in sub pages,
3541     * and content object stack trace.
3542     *
3543     * @throws JahiaException thrown in the case we have trouble creating the
3544     * staged version to flag for deletion.
3545     */

3546    public void markLanguageForDeletion (JahiaUser user,
3547                                         String JavaDoc languageCode,
3548                                         StateModificationContext stateModifContext)
3549            throws JahiaException {
3550
3551        boolean stateModified = false;
3552        Set languageCodes = new HashSet();
3553        if ( stateModifContext.isAllLanguages() ) {
3554            languageCodes.addAll(getStagingLanguages(false));
3555        } else if (willBeCompletelyDeleted (languageCode, null)) {
3556            stateModified = true;
3557            stateModifContext.pushAllLanguages (true);
3558        }
3559
3560        if ( languageCode != null
3561             && !ContentObject.SHARED_LANGUAGE.equals(languageCode) ){
3562            // otherwise we will create unwanted shared lang staged entry !!!!
3563
// should throws Exception here ?
3564
languageCodes.add(languageCode);
3565        }
3566        if ( stateModified && stateModifContext.isAllLanguages()) {
3567            languageCodes.addAll(getStagingLanguages(false));
3568        }
3569
3570        Vector allStagingPageInfos = getAllPageInfosForWrite (languageCodes);
3571
3572        ContentPageKey pageKey = new ContentPageKey (getID ());
3573        boolean stacked = false;
3574
3575        ServicesRegistry sr = ServicesRegistry.getInstance ();
3576
3577        EntryLoadRequest loadRequest =
3578                new EntryLoadRequest (EntryLoadRequest.STAGING_WORKFLOW_STATE, 0,
3579                        new ArrayList ());
3580        switch (getPageType (loadRequest)) {
3581
3582            case JahiaPage.TYPE_DIRECT:
3583
3584                // we must now mark all page related content for deletion, that is to
3585
// say :
3586

3587                // 1. all fields on the page
3588
sr.getJahiaFieldService ().markPageFieldsLanguageForDeletion (getID (),
3589                        user, languageCode, stateModifContext);
3590
3591                // 2. all container lists on the page
3592
sr.getJahiaContainersService ().
3593                        markPageContainerListsLanguageForDeletion (
3594                                getID (),
3595                                user,
3596                                languageCode,
3597                                stateModifContext);
3598
3599                stateModifContext.pushObjectID (pageKey);
3600                stacked = true;
3601
3602                // 3. all links on this page, including the fields they are in AND
3603
// the containers the fields are in.
3604
if ( stateModifContext.isAllLanguages() ){
3605                    // we can only mark for delete page field, if the page is deleted in all langs.
3606
markReferringContentForDeletion(user, languageCode,
3607                        stateModifContext);
3608                }
3609
3610                break;
3611            case JahiaPage.TYPE_LINK:
3612                break;
3613            case JahiaPage.TYPE_URL:
3614                break;
3615        }
3616
3617        // first we must check if there are active versions for the page info
3618
// data. If not, we simply delete directly the existing staging entries
3619
Enumeration allStagingPageInfoEnum = allStagingPageInfos.elements ();
3620        while (allStagingPageInfoEnum.hasMoreElements ()) {
3621            JahiaPageInfo curPageInfo = (JahiaPageInfo) allStagingPageInfoEnum.
3622                                        nextElement();
3623            if (languageCodes.contains(curPageInfo.getLanguageCode())) {
3624                if (mActivePageInfos.containsKey(curPageInfo.getLanguageCode())) {
3625                    if ( curPageInfo.getVersionID()
3626                         != ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED ){
3627                        curPageInfo.setVersionID(-1);
3628                        // Page Move issue here:
3629
// switching to mark for delete without take care to undo
3630
// any page move state create a moved-deleted-phantom page!!!
3631
JahiaPageInfo activePageInfo = (JahiaPageInfo)
3632                                mActivePageInfos.get(curPageInfo.
3633                                getLanguageCode());
3634                        curPageInfo.setParentID(activePageInfo.getParentID());
3635                        curPageInfo.commitChanges(false);
3636                        JahiaPagesDB.getInstance().updatePageInfo(curPageInfo,
3637                                curPageInfo.getVersionID(),
3638                                curPageInfo.getWorkflowState());
3639                    }
3640                } else {
3641                    deleteEntry (curPageInfo);
3642                }
3643            }
3644        }
3645
3646        if (stacked) {
3647            stateModifContext.popObjectID ();
3648        }
3649
3650        if (stateModified) {
3651            stateModifContext.popAllLanguages ();
3652        }
3653
3654    }
3655
3656    private void markReferringContentForDeletion (JahiaUser user,
3657                                                  String JavaDoc languageCode,
3658                                                  StateModificationContext
3659            stateModifContext)
3660            throws JahiaException {
3661
3662        ArrayList locales = new ArrayList ();
3663        locales.add (LanguageCodeConverters.languageCodeToLocale (languageCode));
3664
3665        EntryLoadRequest loadRequest = new EntryLoadRequest (
3666                EntryLoadRequest.STAGING_WORKFLOW_STATE, 0, locales);
3667
3668        Vector referingPages = ServicesRegistry.getInstance ().
3669                getJahiaPageService ().
3670                getPagesPointingOnPage (getID (), loadRequest);
3671
3672        if (stateModifContext.getStartObject ().equals (new ContentPageKey (getID ()))) {
3673            // let's add our own page.
3674
referingPages.add (new JahiaPage (this, getPageTemplate (loadRequest),
3675                    getACL (),
3676                    loadRequest));
3677        }
3678        
3679        Set parentPages = new HashSet();
3680        for (Iterator pagesIterator = referingPages.iterator(); pagesIterator.hasNext();){
3681            parentPages.add(new Integer JavaDoc(((JahiaPage)pagesIterator.next()).getParentID()));
3682        }
3683        
3684        markReferringContentForDeletion (user, languageCode, stateModifContext, referingPages);
3685        
3686        invalidateHtmlCache(parentPages);
3687    }
3688
3689    private void markReferringContentForDeletion (JahiaUser user,
3690                                                  String JavaDoc languageCode,
3691                                                  StateModificationContext
3692            stateModifContext,
3693                                                  Vector referingPages)
3694            throws JahiaException {
3695        Enumeration referingPagesEnum = referingPages.elements ();
3696        while (referingPagesEnum.hasMoreElements ()) {
3697            JahiaPage curPage =
3698                    (JahiaPage) referingPagesEnum.nextElement ();
3699            int curPageFieldID =
3700                    JahiaPageUtilsDB.getInstance ().getPageFieldID (curPage.
3701                    getID ());
3702            if (curPageFieldID != -1) {
3703                markReferringPageFieldLanguageForDeletion (curPageFieldID, user, languageCode,
3704                        stateModifContext);
3705            }
3706        }
3707    }
3708
3709    private void markReferringPageFieldLanguageForDeletion (int curPageFieldID,
3710                                                            JahiaUser user,
3711                                                            String JavaDoc languageCode,
3712                                                            StateModificationContext stateModifContext)
3713            throws JahiaException {
3714        ContentField curPageField =
3715                ContentField.getField (curPageFieldID);
3716        if (curPageField == null) {
3717            logger.debug ("Couldn't find page field " +
3718                    curPageFieldID +
3719                    " pointing on page " + getID () +
3720                    ", ignoring it...");
3721        } else {
3722            // we must now mark this field for deletion.
3723
curPageField.markLanguageForDeletion (
3724                    user, languageCode, stateModifContext);
3725
3726            if (curPageField.getContainerID () > 0) {
3727                // field is inside a container.
3728
try {
3729                    ContentContainer curPageFieldContainer =
3730                            ContentContainer.getContainer (curPageField.
3731                            getContainerID ());
3732                    if (curPageFieldContainer == null) {
3733                        logger.debug (
3734                                "Container (" +
3735                                curPageField.getContainerID ()
3736                                +
3737                                ") for a page field (" +
3738                                curPageFieldID +
3739                                ") that points on page " +
3740                                getID () +
3741                                " couldn't be found, it might have been completely deleted already");
3742                    } else {
3743                        // container was successfully loaded.
3744
// we must now try to mark it for deletion.
3745
curPageFieldContainer.markLanguageForDeletion (
3746                                user,
3747                                languageCode,
3748                                stateModifContext);
3749                    }
3750                } catch (JahiaException je) {
3751                    logger.debug (
3752                            "Container " + curPageField.getContainerID () + " not found in database. This is normal if the container has already previously been marked for deletion in the shared language.");
3753                }
3754            }
3755        }
3756
3757    }
3758
3759    /**
3760     * This method is used to determine if all the active entries of this
3761     * content's childs will be deleted once this object is activated.
3762     *
3763     * @param markDeletedLanguageCode an extra language to be removed, to add
3764     * testing before actually marking for deletion. This may be null in the
3765     * case we just want to test the current state.
3766     * @param activationLanguageCodes a set of language for which we are
3767     * currently activating. May be null if we want to test for all the
3768     * languages, but if specified will test if the object will be completly
3769     * deleted when activated with only those languages.
3770     *
3771     * @return true if in the next activation there will be no active entries
3772     * left.
3773     *
3774     * @throws JahiaException in case there was a problem retrieving the
3775     * entry states from the database
3776     */

3777    public boolean willAllChildsBeCompletelyDeleted (JahiaUser user,
3778                                                     String JavaDoc markDeletedLanguageCode,
3779                                                     Set activationLanguageCodes)
3780            throws JahiaException {
3781        // we are not descending in childs
3782
return true;
3783    }
3784
3785    /**
3786     * Deletes all the page's staging entries. Does not go into page content
3787     * to delete related fields, etc...
3788     *
3789     * @throws JahiaException in the case we have trouble communicating with
3790     * the backend persistant storage for deleting staging versions
3791     * @params jParams used because we have to delete some data in some cases,
3792     * such as pages, fields and containerlists which need the ParamBean
3793     * instance mostly for Event triggering and pageID retrieval
3794     */

3795    public void undoStaging (ParamBean jParams) throws JahiaException {
3796        Vector pageInfosToDelete = new Vector ();
3797        // first let's make a copy of the list to delete otherwise it will
3798
// take forever...
3799
Iterator stagedPageInfoIter = mStagingPageInfos.values ().iterator ();
3800        while (stagedPageInfoIter.hasNext ()) {
3801            JahiaPageInfo curPageInfo = (JahiaPageInfo) stagedPageInfoIter.next ();
3802            pageInfosToDelete.add (curPageInfo);
3803        }
3804
3805        // now that we have the list of pageInfos to delete, let's do it...
3806
Enumeration pageInfosToDeleteEnum = pageInfosToDelete.elements ();
3807        while (pageInfosToDeleteEnum.hasMoreElements ()) {
3808            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfosToDeleteEnum.nextElement ();
3809            // the next call is slow !
3810
deleteEntry (curPageInfo);
3811        }
3812    }
3813
3814    private boolean hasEntry (EntryStateable entryState)
3815            throws JahiaException {
3816        Iterator pageInfoIter = mPageInfos.iterator ();
3817        if ((entryState.getWorkflowState () < ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) &&
3818                (mArchivedPageInfos.size () == 0)) {
3819            ArrayList locales = new ArrayList ();
3820            locales.add (
3821                    LanguageCodeConverters.languageCodeToLocale (entryState.getLanguageCode ()));
3822            EntryLoadRequest loadRequest = new EntryLoadRequest (entryState.getWorkflowState (),
3823                    entryState.getVersionID (), locales);
3824            Vector versionedPageInfos = JahiaPagesDB.getInstance ().loadPageInfos (getID (),
3825                    loadRequest);
3826            // for the moment we just add them to the current list, but we might want to
3827
// dispose of them quickly...
3828
mPageInfos.addAll (versionedPageInfos);
3829            rebuildStatusMaps ();
3830        }
3831        while (pageInfoIter.hasNext ()) {
3832            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
3833            if ((curPageInfo.getWorkflowState () == entryState.getWorkflowState ()) &&
3834                    (curPageInfo.getVersionID () == entryState.getVersionID ()) &&
3835                    (curPageInfo.getLanguageCode ().equals (entryState.getLanguageCode ()))) {
3836                return true;
3837            }
3838        }
3839        return false;
3840    }
3841
3842    /**
3843     * This method is called when a entry should be copied into a new entry
3844     * it is called when an old version -> active version move occurs
3845     * This method should not write/change the DBValue, the service handles that.
3846     *
3847     * @param fromEntryState the entry state that is currently was in the database
3848     * @param toEntryState the entry state that will be written to the database
3849     */

3850    public void copyEntry (EntryStateable fromEntryState,
3851                           EntryStateable toEntryState)
3852            throws JahiaException {
3853        if (hasEntry (toEntryState)) {
3854            deleteEntry (toEntryState);
3855        }
3856        JahiaPagesDB.getInstance ().copyEntry (getID (), fromEntryState, toEntryState);
3857        JahiaPageInfo pageInfo = JahiaPagesDB.getInstance ().loadPageInfo (getID (),
3858                toEntryState);
3859        if (pageInfo != null) {
3860            mPageInfos.add (pageInfo);
3861        }
3862        rebuildStatusMaps ();
3863
3864        ServicesRegistry.getInstance ().getJahiaPageService ().invalidatePageCache (getID ());
3865
3866        // invalidate sitemap cahe too
3867
ServicesRegistry.getInstance ().getJahiaSiteMapService ().resetSiteMap ();
3868    }
3869
3870    /**
3871     * This method is called when an entry should be deleted for real.
3872     * It is called when a field is deleted, and versioning is disabled, or
3873     * when staging values are undone.
3874     * For a bigtext for instance, this method should delete the text file
3875     * corresponding to this field entry.
3876     * Warning : this method is used mostly for use from the ContentPageField
3877     * object ! It is not recommend to use this from any other system as this
3878     * really destroys data and might be very dangerous !
3879     *
3880     * @param deleteEntryState the entry state for which to delete the entry
3881     * @param jParams used because we sometimes need to delete the page
3882     * completly if we are deleting the page's last entry.
3883     *
3884     * @throws JahiaException thrown in the case that we have errors while
3885     * communicating with the persistant storage system
3886     */

3887    public void deleteEntry (EntryStateable deleteEntryState) throws JahiaException {
3888        JahiaPageInfo targetPageInfo = null;
3889
3890        if (deleteEntryState.getWorkflowState () >= EntryLoadRequest.STAGING_WORKFLOW_STATE) {
3891            // case of a staged version
3892
targetPageInfo =
3893                    (JahiaPageInfo) mStagingPageInfos.get (deleteEntryState.getLanguageCode ());
3894            if (targetPageInfo != null) {
3895                JahiaPagesDB.getInstance ().deletePageInfo (targetPageInfo);
3896                removePageInfo (targetPageInfo);
3897            }
3898        } else if (deleteEntryState.getWorkflowState () == EntryLoadRequest.ACTIVE_WORKFLOW_STATE) {
3899            // case of an active version
3900
targetPageInfo =
3901                    (JahiaPageInfo) mActivePageInfos.get (deleteEntryState.getLanguageCode ());
3902            JahiaPagesDB.getInstance ().deletePageInfo (targetPageInfo);
3903            removePageInfo (targetPageInfo);
3904        } else {
3905            // case of an archived version
3906
// first we have to find the archived version, so we load all of them... (ahem)
3907
/** @todo FIXME it would be better not to have to load all the versions... */
3908            ArrayList locales = new ArrayList ();
3909            locales.add (
3910                    LanguageCodeConverters.languageCodeToLocale (
3911                            deleteEntryState.getLanguageCode ()));
3912            EntryLoadRequest deleteEntryRequest = new EntryLoadRequest (
3913                    deleteEntryState.getWorkflowState (), deleteEntryState.getVersionID (),
3914                    locales);
3915            Vector versionedPageInfos = JahiaPagesDB.getInstance ().loadPageInfos (getID (),
3916                    deleteEntryRequest);
3917
3918            // now that we have the archived versions, let's find the one we want to delete
3919
Enumeration versionedPageInfosEnum = versionedPageInfos.elements ();
3920            while (versionedPageInfosEnum.hasMoreElements ()) {
3921                JahiaPageInfo curPageInfo = (JahiaPageInfo) versionedPageInfosEnum.nextElement ();
3922                if ((curPageInfo.getLanguageCode ().equals (deleteEntryState.getLanguageCode ())) &&
3923                        (curPageInfo.getWorkflowState () == deleteEntryState.getWorkflowState ()) &&
3924                        (curPageInfo.getVersionID () == deleteEntryState.getVersionID ())) {
3925                    // we found the archived version to delete, let's do it.
3926
targetPageInfo = curPageInfo;
3927                    JahiaPagesDB.getInstance ().deletePageInfo (curPageInfo);
3928                    removePageInfo (curPageInfo);
3929                    break;
3930                }
3931            }
3932        }
3933        ServicesRegistry.getInstance ().getJahiaPageService ().invalidatePageCache (getID ());
3934        // invalidate sitemap cahe too
3935
ServicesRegistry.getInstance ().getJahiaSiteMapService ().resetSiteMap ();
3936    }
3937
3938    /**
3939     * Returns true if the page has active entries
3940     *
3941     * @return true if their are entries in an active workflowState for this
3942     * page
3943     */

3944    public boolean hasActiveEntries () {
3945        if (mActivePageInfos.size () > 0) {
3946            return true;
3947        } else {
3948            return false;
3949        }
3950    }
3951
3952    /**
3953     * Returns true if the page has staging entries
3954     *
3955     * @return true if their are entries in an staging workflowState for this
3956     * page
3957     */

3958    public boolean hasStagingEntries () {
3959        if (this.mStagingPageInfos.size () > 0) {
3960            return true;
3961        } else {
3962            return false;
3963        }
3964    }
3965
3966    /**
3967     * Use these constants in association with the 'hasEntries' methods to set
3968     * which kind of page infos are contained in the entries.
3969     */

3970    public static final int ACTIVE_PAGE_INFOS = 0x01;
3971    public static final int STAGING_PAGE_INFOS = 0x02;
3972    public static final int ARCHIVED_PAGE_INFOS = 0x04;
3973
3974    /**
3975     * Return true if the page has specified 'pageInfos' entries in the specified
3976     * language.
3977     *
3978     * @param pageInfosFlag Kind of page infos desired. This parameter can associate
3979     * the previous constants. For example ACTIVE_PAGE_INFOS | STAGING_PAGE_INFOS
3980     * look for both active and staged pages and return the appropriate result.
3981     * @param languageCode The specified language code.
3982     *
3983     * @return True if it is at least one entry for this page.
3984     */

3985    public boolean hasEntries (int pageInfosFlag, String JavaDoc languageCode) {
3986        boolean hasEntries = false;
3987        if ((pageInfosFlag & 0x01) != 0) {
3988            hasEntries = mActivePageInfos.containsKey (languageCode);
3989        }
3990        if ((pageInfosFlag & 0x02) != 0) {
3991            hasEntries |= mStagingPageInfos.containsKey (languageCode);
3992        }
3993        if ((pageInfosFlag & 0x04) != 0) {
3994            // ensure to load versioning entries
3995
try {
3996                loadVersioningEntryStates ();
3997            } catch (Throwable JavaDoc t) {
3998                logger.debug ("Exception ocured loading versining entries", t);
3999            }
4000            hasEntries |= hasArchivedPageInfos (languageCode);
4001        }
4002        if ((pageInfosFlag & 0x08) != 0) {
4003            hasEntries = mActivePageInfos.containsKey (languageCode);
4004            if (hasEntries) {
4005                return true;
4006            }
4007            hasEntries = mStagingPageInfos.containsKey (languageCode);
4008            if (hasEntries) {
4009                return true;
4010            }
4011            // ensure to load versioning entries
4012
try {
4013                loadVersioningEntryStates ();
4014            } catch (Throwable JavaDoc t) {
4015                logger.debug ("Exception ocured loading versining entries", t);
4016            }
4017            return hasArchivedPageInfos (languageCode);
4018        }
4019        return hasEntries;
4020    }
4021
4022    /**
4023     * Return true if the page has specified 'pageInfos' entries.
4024     *
4025     * @param pageInfosFlag Kind of page infos desired. This parameter can associate
4026     * the previous constants. For example ACTIVE_PAGE_INFOS | STAGING_PAGE_INFOS
4027     * look for both active and staged pages and return the appropriate result.
4028     *
4029     * @return True if it is at least one entry for this page.
4030     */

4031    public boolean hasEntries (int pageInfosFlag) {
4032        boolean hasEntries = false;
4033        if ((pageInfosFlag & 0x01) != 0) {
4034            hasEntries = mActivePageInfos.size () > 0;
4035        }
4036        if ((pageInfosFlag & 0x02) != 0) {
4037            hasEntries |= mStagingPageInfos.size () > 0;
4038        }
4039        if ((pageInfosFlag & 0x04) != 0) {
4040            // ensure to load versioning entries
4041
try {
4042                loadVersioningEntryStates ();
4043            } catch (Throwable JavaDoc t) {
4044                logger.debug ("Exception ocured loading versining entries", t);
4045            }
4046            hasEntries |= mArchivedPageInfos.size () > 0;
4047        }
4048        return hasEntries;
4049    }
4050
4051    /**
4052     * Returns the versionID at which the page is deleted.
4053     *
4054     * @return -1 if the page is not actually deleted otherwise the versionID of the
4055     * last delete operation.
4056     *
4057     * @throws JahiaException
4058     */

4059    public int getDeleteVersionID () throws JahiaException {
4060        int versionID = -1;
4061        SortedSet entryStates = this.getEntryStates ();
4062        Iterator iterator = entryStates.iterator ();
4063        ContentObjectEntryState curEntryState = null;
4064        ContentObjectEntryState resultEntryState = null;
4065
4066        while (iterator.hasNext ()) {
4067            curEntryState = (ContentObjectEntryState) iterator.next ();
4068            if (curEntryState.getWorkflowState ()
4069                    == ContentObjectEntryState.WORKFLOW_STATE_ACTIVE) {
4070                return -1;
4071            }
4072            if (curEntryState.getWorkflowState ()
4073                    == ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED) {
4074                if (resultEntryState == null) {
4075                    resultEntryState = curEntryState;
4076                } else {
4077                    if (resultEntryState.getVersionID () < curEntryState.getVersionID ()) {
4078                        resultEntryState = curEntryState;
4079                    }
4080                }
4081            }
4082        }
4083        if (resultEntryState != null) {
4084            versionID = resultEntryState.getVersionID ();
4085        }
4086        return versionID;
4087    }
4088
4089    /**
4090     * Returns true if the page was deleted at a given versionID for all lang.
4091     */

4092    public boolean wasDeleted (int versionID) throws JahiaException {
4093        SortedSet entryStates = this.getEntryStates ();
4094        Iterator iterator = entryStates.iterator ();
4095        while (iterator.hasNext ()) {
4096            ContentObjectEntryState curEntryState = (ContentObjectEntryState) iterator.next ();
4097            if (curEntryState.getWorkflowState ()
4098                    != ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED
4099                    && curEntryState.getVersionID () == versionID) {
4100                // we found an entry that is not deleted
4101
// this can be the case if we deleted some language but not all
4102
return false;
4103            }
4104        }
4105        return true;
4106    }
4107
4108    /**
4109     * Return true if the staged entry is mark for deletion.
4110     *
4111     * @param languageCode The language code where the page is mark for deletion.
4112     *
4113     * @return True if the staged entry is mark for deletion (is == -1).
4114     *
4115     * @todo Please improve this code. Is the languageCode param really needed.
4116     */

4117    public boolean isStagedEntryMarkedForDeletion (String JavaDoc languageCode) {
4118        JahiaPageInfo pageInfo = (JahiaPageInfo) mStagingPageInfos.get (languageCode);
4119        return pageInfo != null &&
4120                pageInfo.getVersionID () == EntryLoadRequest.DELETED_WORKFLOW_STATE ?
4121                true : false;
4122    }
4123
4124    /**
4125     * Returns the value of all the languages states for a given page. This is
4126     * used to know at what stage of workflow languages of a page currently are.
4127     *
4128     * @param withContent if this is true, the value returned will correspond
4129     * to a logical OR of the staging workflow states of the page itself with
4130     * the page's content (for the moment just the fields are check as the
4131     * containers should have the same staging workflow state). Use this if
4132     * you want to know whether a page needs validation of all of it's content.
4133     *
4134     * @return a hash map containing language codes as keys, and as values
4135     * Integer objects containing the state of each language.
4136     */

4137    public Map getLanguagesStates (boolean withContent) {
4138        /* FIXME : we roolback a bit in optimization in order to have something stable
4139         * before implementing harsh optimization
4140
4141        if (languageStateCache != null) {
4142            long nowDate = new Date().getTime();
4143            if (nowDate <= (langStateCacheLastAccess + LANGSTATECACHE_EXPIRATIONDELAY)) {
4144                langStateCacheLastAccess = nowDate;
4145                return languageStateCache;
4146            } else {
4147                languageStateCache = null;
4148            }
4149        }*/

4150        Map result = new HashMap();
4151        Iterator pageInfoIter = mStagingPageInfos.entrySet().iterator ();
4152        while (pageInfoIter.hasNext ()) {
4153          Map.Entry curEntry = (Map.Entry)pageInfoIter.next ();
4154          result.put(curEntry.getKey(),
4155            new Integer JavaDoc(((JahiaPageInfo)curEntry.getValue()).getWorkflowState()));
4156        }
4157        
4158        pageInfoIter = mActivePageInfos.entrySet().iterator ();
4159        while (pageInfoIter.hasNext ()) {
4160          Map.Entry curEntry = (Map.Entry)pageInfoIter.next ();
4161          if (!result.containsKey(curEntry.getKey())) {
4162            result.put(curEntry.getKey(),
4163              new Integer JavaDoc(((JahiaPageInfo)curEntry.getValue()).getWorkflowState()));
4164          }
4165        }
4166
4167        pageInfoIter = mArchivedPageInfos.iterator ();
4168        while (pageInfoIter.hasNext ()) {
4169            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
4170            Integer JavaDoc resultState = (Integer JavaDoc) result.get (curPageInfo.getLanguageCode ());
4171            if (resultState != null) {
4172                if (resultState.intValue () < curPageInfo.getWorkflowState ()) {
4173                    result.put (curPageInfo.getLanguageCode (),
4174                            new Integer JavaDoc (curPageInfo.getWorkflowState ()));
4175                }
4176            } else {
4177                result.put (curPageInfo.getLanguageCode (),
4178                        new Integer JavaDoc (curPageInfo.getWorkflowState ()));
4179            }
4180        }
4181
4182        if (withContent) {
4183            try {
4184                Map fieldsLanguagesStates = ServicesRegistry.getInstance ()
4185                        .getJahiaFieldService ()
4186                        .getFieldsLanguagesState (getID ());
4187
4188                result = mergeLanguageStates (result, fieldsLanguagesStates);
4189
4190// long beforeContainersState = new Date().getTime();
4191
//
4192
// Map containersLanguagesStates = ServicesRegistry.getInstance ()
4193
// .getJahiaContainersService ()
4194
// .getContainersLanguagesState (getID ());
4195
//
4196
// long afterContainersState = new Date().getTime();
4197
// logger.debug("Time to retrieve container state=" + Long.toString(afterContainersState - beforeContainersState) + "ms");
4198
//
4199
// result = mergeLanguageStates (result, containersLanguagesStates);
4200
} catch (JahiaException je) {
4201                logger.debug ("Error while retrieving language workflow states", je);
4202            }
4203
4204
4205/* commented out because we're probably going to do this another way.
4206
4207            // now that we've check the state of local page content, let's check
4208            // the state of the content that is included from other pages.
4209
4210            // we will need the site throughout these operations so we get
4211            // that first.
4212            try {
4213                JahiaSite thisSite = ServicesRegistry.getInstance().getJahiaSitesService().getSite(getJahiaID());
4214
4215                // now let's do it for absolute addresses fields
4216                Set fieldKeys = FieldXRefManager.getInstance().getAbsoluteFieldsFromPageID(thisSite.getSiteKey(), getID());
4217                Iterator fieldKeyIter = fieldKeys.iterator();
4218                while (fieldKeyIter.hasNext()) {
4219                    FieldKey curFieldKey = (FieldKey) fieldKeyIter.next();
4220                    int fieldID = ServicesRegistry.getInstance().getJahiaFieldService().getFieldID(curFieldKey.getFieldName(), curFieldKey.getFieldSourcePageID());
4221                    ContentField curField = ContentField.getField(fieldID);
4222                    Map languageStates = curField.getLanguagesStates();
4223                    result = mergeLanguageStates ( result, languageStates );
4224                }
4225
4226                // and now for absolute addressed containers
4227                Set containerListKeys = ContainerListsXRefManager.getInstance().getAbsoluteContainerListsFromPageID(thisSite.getSiteKey(), getID());
4228                Iterator containerListKeyIter = containerListKeys.iterator();
4229                while (containerListKeyIter.hasNext()) {
4230                    ContainerListKey curContainerListKey = (ContainerListKey) containerListKeyIter.next();
4231                    int containerListID = ServicesRegistry.getInstance().getJahiaContainersService().getContainerListID(curContainerListKey.getContainerListName(), curContainerListKey.getContainerListSourcePageID());
4232                    Vector containerIDs = ServicesRegistry.getInstance().getJahiaContainersService().getctnidsInList(containerListID);
4233                    Enumeration containerIDEnum = containerIDs.elements();
4234                    while (containerIDEnum.hasMoreElements()) {
4235                        Integer curContainerID = (Integer) containerIDEnum.nextElement();
4236                        Vector fieldIDs = ServicesRegistry.getInstance().getJahiaContainersService().getFieldIDsInContainer(curContainerID.intValue());
4237                        Enumeration fieldIDEnum = fieldIDs.elements();
4238                        while (fieldIDEnum.hasMoreElements()) {
4239                            Integer curFieldID = (Integer) fieldIDEnum.nextElement();
4240                            ContentField curField = ContentField.getField(curFieldID.intValue());
4241                            Map languageStates = curField.getLanguagesStates();
4242                            result = mergeLanguageStates ( result, languageStates );
4243                        }
4244                    }
4245
4246                }
4247            } catch (JahiaException je) {
4248                logger.debug("Error while accessing site for page " + getID(), je);
4249            }
4250*/

4251        }
4252
4253        return result;
4254    }
4255
4256    /**
4257     * Flushes the internal language state cache. Use this if the cache expiration
4258     * delay is not low enough and you need to flush this faster.
4259     */

4260    public void flushLanguageStateCache() {
4261    }
4262
4263    /**
4264     * Merges two language states map. Warning : this modifies the destination
4265     * map so you'll want to be careful using this code and maybe clone maps
4266     * before using it.
4267     *
4268     * @param destination the destination languageStates map
4269     * @param source the source languageState map that contains the languages
4270     * states to add to the destination
4271     *
4272     * @return the destination map modified by merging the source languageStates
4273     * map.
4274     */

4275    private Map mergeLanguageStates (Map destination, Map source) {
4276        Iterator sourceIter = source.keySet ().iterator ();
4277        while (sourceIter.hasNext ()) {
4278            String JavaDoc curLanguageCode = (String JavaDoc) sourceIter.next ();
4279            Integer JavaDoc languageState = (Integer JavaDoc) source.get (curLanguageCode);
4280            Integer JavaDoc resultState = (Integer JavaDoc) destination.get (curLanguageCode);
4281            if (resultState != null) {
4282                if (resultState.intValue () < languageState.intValue ()) {
4283                    destination.put (curLanguageCode, languageState);
4284                }
4285            } else {
4286                destination.put (curLanguageCode, languageState);
4287            }
4288        }
4289
4290        return destination;
4291
4292    }
4293
4294    /**
4295     * Look if the child page given by its ID has 'this' Jahia page content object
4296     * as parent.
4297     *
4298     * @param jParams
4299     * @param childPageID The child page in question
4300     *
4301     * @return True if 'this' is parent of child page ID.
4302     */

4303    public boolean isParentPage (EntryLoadRequest loadRequest, int childPageID) {
4304        int pageID = childPageID;
4305        try {
4306            do {
4307                ContentPage page = ServicesRegistry.getInstance ().getJahiaPageService ().lookupContentPage (pageID, false);
4308                if (pageID == getID ()) {
4309                    return true;
4310                }
4311                pageID = page.getParentID (loadRequest);
4312            } while (pageID != 0);
4313        } catch (JahiaException je) {
4314            logger.debug ("Page not found !! (Das isch doch komisch, gal)", je);
4315        }
4316        return false;
4317    }
4318
4319    /**
4320     * @param jParams
4321     * @param childPageID
4322     *
4323     * @return
4324     */

4325    public boolean isParentPage (ParamBean jParams, int childPageID) {
4326        if (jParams != null) {
4327            return isParentPage (jParams.getEntryLoadRequest (), childPageID);
4328        } else {
4329            logger.debug ("FIXME : Method called with null ParamBean, returning false");
4330            return false;
4331        }
4332    }
4333
4334    /**
4335     * Writes an XML serialization version of this content page, according to
4336     * the seriliazation options specified. This is very useful for exporting
4337     * Jahia content to external systems.
4338     *
4339     * @param xmlWriter the XML writer object in which to output the XML
4340     * exported data
4341     * @param xmlSerializationOptions the options that activate/deactivate
4342     * parts of the XML exported data.
4343     * @param paramBean specifies context of serialization, such as current
4344     * user, current request parameters, entry load request, URL generation
4345     * information such as ServerName, ServerPort, ContextPath, etc... URL
4346     * generation is an important part of XML serialization and this is why
4347     * we pass this parameter down, as well as user rights checking.
4348     *
4349     * @throws IOException upon error writing to the XMLWriter
4350     * @todo FIXME : only container lists output for the moment. Still to be
4351     * done are page fields.
4352     * @todo getPageType actually passed a null EntryLoadRequest !!
4353     */

4354    public synchronized void serializeToXML (XmlWriter xmlWriter,
4355                                             XMLSerializationOptions
4356            xmlSerializationOptions,
4357                                             ParamBean paramBean)
4358            throws IOException JavaDoc {
4359        xmlWriter.writeEntity ("contentPage");
4360        String JavaDoc pageType;
4361        switch (getPageType (null)) {
4362            case JahiaPage.TYPE_DIRECT:
4363                pageType = "direct";
4364                break;
4365            case JahiaPage.TYPE_LINK:
4366                pageType = "link";
4367                break;
4368            case JahiaPage.TYPE_URL:
4369                pageType = "url";
4370                break;
4371            default :
4372                pageType = "unknown";
4373                break;
4374        }
4375        xmlWriter.writeAttribute ("type", pageType);
4376
4377        xmlWriter.writeEntity ("titles");
4378        Hashtable pageTitles = getTitles (ContentPage.ACTIVATED_PAGE_TITLES);
4379        Enumeration pageTitleEnum = pageTitles.keys ();
4380        while (pageTitleEnum.hasMoreElements ()) {
4381            String JavaDoc curLanguageCode = (String JavaDoc) pageTitleEnum.nextElement ();
4382            String JavaDoc curTitle = (String JavaDoc) pageTitles.get (curLanguageCode);
4383            xmlWriter.writeEntity ("title").
4384                    writeAttribute ("language", curLanguageCode);
4385            xmlWriter.writeText (curTitle);
4386            xmlWriter.endEntity ();
4387        }
4388        xmlWriter.endEntity ();
4389
4390        switch (getPageType (null)) {
4391            case JahiaPage.TYPE_DIRECT:
4392                xmlWriter.writeEntity ("direct");
4393                if (xmlSerializationOptions.isIncludingSubPages ()) {
4394                    ServicesRegistry sr = ServicesRegistry.getInstance ();
4395                    sr.getJahiaFieldService ().serializeNonContainerFieldsToXML (xmlWriter,
4396                            xmlSerializationOptions, getID (), paramBean);
4397                    sr.getJahiaContainersService ().serializePageContainerListsToXML (
4398                            xmlWriter, xmlSerializationOptions, getID (), paramBean);
4399                }
4400                xmlWriter.endEntity ();
4401                break;
4402            case JahiaPage.TYPE_LINK:
4403                xmlWriter.writeEntityWithText ("link",
4404                        Integer.toString (getPageLinkID (EntryLoadRequest.CURRENT)));
4405                break;
4406            case JahiaPage.TYPE_URL:
4407                xmlWriter.writeEntityWithText ("url", getRemoteURL (EntryLoadRequest.CURRENT));
4408                break;
4409        }
4410        xmlWriter.endEntity ();
4411    }
4412
4413    /**
4414     * Returns an iterator on a sorted Set of entry states that correspond to
4415     * the all the entry states for the page object. To get page content object
4416     * entry states use the getChilds method.
4417     *
4418     * @return a SortedSet of ContentFieldEntryState objects that contain the
4419     * entry state information for all the content on the page
4420     *
4421     * @throws JahiaException thrown if there was a problem loading entry state
4422     * information from the database.
4423     */

4424    public SortedSet getEntryStates ()
4425            throws JahiaException {
4426        SortedSet entryStates = new TreeSet ();
4427
4428        loadVersioningEntryStates ();
4429
4430        // now we need to convert all this data to EntryState format.
4431
Iterator pageInfoIter = mPageInfos.iterator ();
4432        while (pageInfoIter.hasNext ()) {
4433            JahiaPageInfo curPageInfo = (JahiaPageInfo) pageInfoIter.next ();
4434            ContentObjectEntryState entryState = new ContentObjectEntryState (
4435                    curPageInfo.getWorkflowState (), curPageInfo.getVersionID (),
4436                    curPageInfo.getLanguageCode ());
4437            entryStates.add (entryState);
4438        }
4439
4440        return entryStates;
4441    }
4442
4443    /**
4444     * Returns the biggest versionID of the active entry, 0 if doesn't exist
4445     *
4446     * @return
4447     *
4448     * @throws JahiaException
4449     */

4450    public int getActiveVersionID ()
4451            throws JahiaException {
4452        int versionID = 0;
4453        Iterator iterator = this.mActivePageInfos.values ().iterator ();
4454        JahiaPageInfo pageInfo = null;
4455        while (iterator.hasNext ()) {
4456            pageInfo = (JahiaPageInfo) iterator.next ();
4457            if ( pageInfo.getVersionID() > versionID ){
4458                versionID = pageInfo.getVersionID();
4459            }
4460        }
4461        return versionID;
4462    }
4463
4464    /*
4465     *
4466     * @throws JahiaException
4467     */

4468    private synchronized void loadVersioningEntryStates () throws JahiaException {
4469        //if ( this.mArchivedPageInfos.size() == 0 ){
4470
if (this.mArchivedPageInfos == null) {
4471            this.mArchivedPageInfos = new HashSet ();
4472            Vector versionedPageInfos = JahiaPagesDB.getInstance ().loadPageInfos (getID (),
4473                    EntryLoadRequest.VERSIONED);
4474            int size = versionedPageInfos.size ();
4475            for (int i = 0; i < size; i++) {
4476                JahiaPageInfo pageInfo = (JahiaPageInfo) versionedPageInfos.get (i);
4477                this.mArchivedPageInfos.add (pageInfo);
4478            }
4479            if (versionedPageInfos.size () > 0) {
4480                mPageInfos.addAll (versionedPageInfos);
4481                rebuildStatusMaps ();
4482            }
4483        }
4484    }
4485
4486    public RestoreVersionTestResults isValidForRestore (JahiaUser user,
4487                                                        String JavaDoc operationMode,
4488                                                        ContentObjectEntryState entryState,
4489                                                        boolean removeMoreRecentActive,
4490                                                        StateModificationContext stateModificationContext)
4491            throws JahiaException {
4492
4493        RestoreVersionTestResults opResult = new RestoreVersionTestResults ();
4494        /**
4495         * This test has no meaning because the language could miss for this object but
4496         * we should be able to restore other content ( fields,... )
4497         // first let's check if we have entries that correspond for this
4498         // page
4499         opResult.merge(super.isValidForRestore(user, operationMode, entryState, removeMoreRecentActive, stateModificationContext));
4500         if (opResult.getStatus() == RestoreVersionTestResults.FAILED_OPERATION_STATUS) {
4501         return opResult;
4502         }*/

4503
4504        switch (getPageType (null)) {
4505            case JahiaPage.TYPE_DIRECT:
4506                if (!stateModificationContext.isDescendingInSubPages () &&
4507                        !stateModificationContext.getStartObject ().equals (new
4508                                ContentPageKey (getID ()))) {
4509                    // we are not descending in sub pages and this is not the
4510
// start point.
4511
opResult.setStatus (RestoreVersionTestResults.
4512                            FAILED_OPERATION_STATUS);
4513                    opResult.appendError (
4514                            new RestoreVersionNodeTestResult (
4515                                    getObjectKey (), entryState.getLanguageCode (),
4516                                    "Cannot restore sub page since recursive activation hasn't been requested"));
4517                    return opResult;
4518                }
4519
4520                // now let's check for the children of this page. If only
4521
// one of them fails, we fail the whole page.
4522
ArrayList locales = new ArrayList ();
4523                locales.add (LanguageCodeConverters.languageCodeToLocale (
4524                        ContentObject.SHARED_LANGUAGE));
4525                locales.add (LanguageCodeConverters.languageCodeToLocale (
4526                        entryState.getLanguageCode ()));
4527                EntryLoadRequest loadRequest = new EntryLoadRequest (entryState.
4528                        getWorkflowState (), entryState.getVersionID (), locales);
4529                ArrayList children = getChilds (user, loadRequest);
4530                ListIterator childrenIter = children.listIterator ();
4531                while (childrenIter.hasNext ()) {
4532                    ContentObject curChild = (ContentObject) childrenIter.next ();
4533                    RestoreVersionTestResults childResult = curChild.isValidForRestore (user,
4534                            operationMode, entryState, removeMoreRecentActive,
4535                            stateModificationContext);
4536                    if (childResult.getStatus () == RestoreVersionTestResults.FAILED_OPERATION_STATUS) {
4537                        childResult.setStatus (
4538                                RestoreVersionTestResults.PARTIAL_OPERATION_STATUS);
4539                        childResult.moveErrorsToWarnings ();
4540                    }
4541                    opResult.merge (childResult);
4542                }
4543
4544                break;
4545            case JahiaPage.TYPE_LINK:
4546            case JahiaPage.TYPE_URL:
4547                break;
4548        }
4549        return opResult;
4550    }
4551
4552    /**
4553     * Return false it this page cannot be reached for given operationMode
4554     * and languageCode.
4555     * In example, if the operationMode is EDIT and the user has no write access
4556     * and this page doesn't exist in ACTIVE mode, the result is false.
4557     *
4558     * @param operationMode
4559     * @param languageCode
4560     * @param user
4561     *
4562     * @return
4563     */

4564    public boolean isReachable (String JavaDoc operationMode, String JavaDoc languageCode,
4565                                JahiaUser user) {
4566        try {
4567            String JavaDoc opMode = operationMode;
4568            if (opMode.equals (ParamBean.EDIT)) {
4569                if (!checkWriteAccess (user)) {
4570                    opMode = ParamBean.NORMAL;
4571                }
4572                if (opMode.equals (ParamBean.NORMAL)) {
4573                    // does the page exist in active state
4574
if (!hasEntries (ContentPage.ACTIVE_PAGE_INFOS,
4575                            languageCode)) {
4576                        return false;
4577                    }
4578                }
4579            }
4580            if (opMode.equals (ParamBean.NORMAL) &&
4581                    !hasEntries (ContentPage.ACTIVE_PAGE_INFOS,
4582                            languageCode)) {
4583                return false;
4584            }
4585        } catch (Throwable JavaDoc t) {
4586            logger.debug ("Exception checking page reachability", t);
4587            return false;
4588        }
4589        return true;
4590    }
4591
4592    /**
4593     * Use this method to control whether we should reparent the page when
4594     * restoring or not ( page move issue ) and if content should be restored
4595     * or not.
4596     * Note : these attributes are local to this content page, they are not
4597     * propagated to sub pages.
4598     *
4599     * @param user
4600     * @param operationMode
4601     * @param entryState
4602     * @param removeMoreRecentActive
4603     * @param restoreContent, if false, restore only page attribute without content
4604     * @param stateModificationContext
4605     * @return
4606     * @throws JahiaException
4607     */

4608    public RestoreVersionTestResults restoreVersion (JahiaUser user,
4609        String JavaDoc operationMode,
4610        ContentObjectEntryState entryState,
4611        boolean removeMoreRecentActive,
4612        boolean restoreContent,
4613        RestoreVersionStateModificationContext stateModificationContext)
4614        throws JahiaException {
4615        this.mRestoreContent = restoreContent;
4616        return restoreVersion(user,operationMode,entryState,removeMoreRecentActive,
4617        stateModificationContext);
4618    }
4619
4620    public RestoreVersionTestResults restoreVersion (JahiaUser user,
4621        String JavaDoc operationMode,
4622        ContentObjectEntryState entryState,
4623        boolean removeMoreRecentActive,
4624        RestoreVersionStateModificationContext stateModificationContext)
4625        throws JahiaException {
4626
4627        RestoreVersionTestResults opResult = new RestoreVersionTestResults();
4628
4629        ContentObjectEntryState closestVersion = null;
4630
4631        // Check if we are doing an undelete
4632
int deleteVersionID = this.getDeleteVersionID();
4633        boolean undeletePage = false;
4634        if (!removeMoreRecentActive && deleteVersionID != -1
4635            && entryState.getVersionID() == deleteVersionID) {
4636            undeletePage = true;
4637            // the page was deleted and we want to restore it
4638
// to do that, we want get the closest entry state before the delete date
4639
closestVersion = this.getClosestVersionedEntryState(entryState, true);
4640            if ( closestVersion != null ){
4641                entryState = closestVersion;
4642            }
4643        }
4644
4645        // do not allow mark for deletion on pages that are home page of a site
4646
boolean allowRemoveMoreRecentActive = removeMoreRecentActive;
4647        if (this.getParentID(new EntryLoadRequest(entryState)) == 0) {
4648            allowRemoveMoreRecentActive = false;
4649        }
4650
4651        // retrieve the exact archive entry state
4652
closestVersion = getClosestVersionedEntryState(entryState);
4653        boolean markedForDelete = false;
4654        boolean isMoreRecentOrWasDeleted = closestVersion == null ||
4655            closestVersion.getWorkflowState() ==
4656            ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED
4657            || !this.hasArchiveEntryState(entryState.getVersionID());
4658
4659        if (!removeMoreRecentActive) {
4660            if (closestVersion != null && closestVersion.getWorkflowState() ==
4661                ContentObjectEntryState.WORKFLOW_STATE_VERSIONING_DELETED) {
4662                // was deleted, or doesn't exist in this language so stop restore deleted content
4663
return opResult;
4664            }
4665        }
4666        else {
4667            // apply an exact restore
4668
// -> remove more recent data or apply deleted archive state when restoring.
4669
if (isMoreRecentOrWasDeleted) {
4670
4671                if (allowRemoveMoreRecentActive) {
4672                    // check if this page is not actually staged ( mainly
4673
// if it's involved in a move ), if so we undo any temporary
4674
// page move state first.
4675

4676                    // mark active for delete
4677
Set langs = new HashSet();
4678                    langs.add(entryState.getLanguageCode());
4679                    RestoreVersionStateModificationContext
4680                        markForDeleteStateModifContext =
4681                        new RestoreVersionStateModificationContext(this.
4682                        getObjectKey(), langs, false, entryState);
4683
4684                    if ( !this.hasArchiveEntryState(entryState.getVersionID(),true) ){
4685                        markForDeleteStateModifContext.pushAllLanguages(true);
4686                    }
4687
4688                    // we want to remove only this language
4689
this.markLanguageForDeletion(user,
4690                                                 entryState.getLanguageCode(),
4691                                                 markForDeleteStateModifContext);
4692                    markedForDelete = true;
4693                }
4694            }
4695        }
4696
4697        if (!markedForDelete && this.mRestoreContent) {
4698
4699            // first let's restore the content on the page
4700
switch (getPageType(null)) {
4701                case JahiaPage.TYPE_DIRECT:
4702                    if (!removeMoreRecentActive &&
4703                        !stateModificationContext.isDescendingInSubPages() &&
4704                        !stateModificationContext.getStartObject().equals(new
4705                        ContentPageKey(getID()))) {
4706                        // we are not descending in sub pages and this is not the
4707
// start point.
4708
opResult.setStatus(RestoreVersionTestResults.
4709                                           FAILED_OPERATION_STATUS);
4710                        opResult.appendError(new RestoreVersionNodeTestResult(
4711                            getObjectKey(), entryState.getLanguageCode(),
4712                            "Cannot restore sub page since recursive activation hasn't been requested"));
4713                        return opResult;
4714                    }
4715
4716                    // now let's check for the children of this page. If only
4717
// one of them fails, we fail the whole page.
4718
ArrayList locales = new ArrayList();
4719                    locales.add(LanguageCodeConverters.languageCodeToLocale(
4720                        ContentObject.SHARED_LANGUAGE));
4721                    locales.add(LanguageCodeConverters.languageCodeToLocale(
4722                        entryState.getLanguageCode()));
4723                    EntryLoadRequest loadRequest = null;
4724
4725                    // 1. First restore archive
4726
// load archive to restore
4727
loadRequest = new EntryLoadRequest(entryState.
4728                        getWorkflowState(), entryState.getVersionID(), locales);
4729                    ArrayList children = getChilds(user, loadRequest);
4730
4731                    // For performance issue, we don't want to restore twice objects.
4732
ArrayList processedChilds = new ArrayList();
4733
4734                    ListIterator childrenIter = children.listIterator();
4735                    while (childrenIter.hasNext()) {
4736                        ContentObject curChild = (ContentObject) childrenIter.
4737                            next();
4738                        opResult.merge(curChild.restoreVersion(user,
4739                            operationMode, entryState, (removeMoreRecentActive),
4740                            stateModificationContext));
4741                        processedChilds.add(curChild.getObjectKey().toString());
4742                    }
4743
4744                    //2.Second, remove more recent data
4745
if (removeMoreRecentActive) {
4746                        // load staging or active to perform a restore which will mark them for delete
4747
loadRequest =
4748                            new EntryLoadRequest(EntryLoadRequest.
4749                                                 STAGING_WORKFLOW_STATE,
4750                                                 0, locales);
4751                        children = getChilds(user, loadRequest);
4752                        childrenIter = children.listIterator();
4753                        while (childrenIter.hasNext()) {
4754                            ContentObject curChild = (ContentObject)
4755                                childrenIter.next();
4756
4757                            if (!processedChilds.contains(curChild.getObjectKey().
4758                                toString())) {
4759                                opResult.merge(curChild.restoreVersion(user,
4760                                    operationMode, entryState,
4761                                    removeMoreRecentActive,
4762                                    stateModificationContext));
4763                            }
4764                        }
4765                    }
4766
4767                    // performance issue, we allow page preloading of fields for this page
4768
ServicesRegistry.getInstance().getJahiaFieldService()
4769                        .allowFieldsPreloadingForPage(this.getID());
4770
4771                    break;
4772                case JahiaPage.TYPE_LINK:
4773                case JahiaPage.TYPE_URL:
4774                    break;
4775            }
4776        }
4777
4778        // now let's restore the page's entry data. We might have to do this
4779
// for more than one entry state if we are restoring information that
4780
// contains moves, page template changes, remote URL or link ID changes,
4781
// or any shared language parameter.
4782

4783        // So first we determine if we are doing operations on just a language
4784
// code or the full set of languages.
4785

4786        JahiaPageInfo versionedPageInfo = getPageInfo(closestVersion);
4787        // now let's get any active entry that we currently have for this page
4788
// if there exists at least one.
4789
JahiaPageInfo anyStagingOrActivePageInfo = null;
4790        if (mStagingPageInfos.size() > 0) {
4791            anyStagingOrActivePageInfo =
4792                (JahiaPageInfo) mStagingPageInfos.values().iterator().next();
4793        }
4794        else if (mActivePageInfos.size() > 0) {
4795            anyStagingOrActivePageInfo =
4796                (JahiaPageInfo) mActivePageInfos.values().iterator().next();
4797        }
4798
4799        if (this.getDeleteVersionID() != -1 ||
4800            ( (anyStagingOrActivePageInfo != null && versionedPageInfo != null)
4801             &&
4802             ( (anyStagingOrActivePageInfo.getPageLinkID() !=
4803                versionedPageInfo.getPageLinkID()) ||
4804              (anyStagingOrActivePageInfo.getPageTemplateID() !=
4805               versionedPageInfo.getPageTemplateID()) ||
4806              (anyStagingOrActivePageInfo.getPageType() !=
4807               versionedPageInfo.getPageType()) ||
4808              (anyStagingOrActivePageInfo.getParentID() !=
4809               versionedPageInfo.getParentID()) ||
4810              remoteURLisDiff(anyStagingOrActivePageInfo.getRemoteURL(),
4811                              versionedPageInfo.getRemoteURL())))) {
4812            // major shared-language change detected, we must perform the
4813
// restores for all the languages.
4814

4815            // the trick here is to correctly identify all the languages for
4816
// which we must restore. This set of language is actually the
4817
// combination of the active entry states and the versioned entry
4818
// state languages. If there are more languages in the active
4819
// entries then they will be marked for deletion since they didn't
4820
// exist in the past.
4821
Set onlyActiveLanguageCodes = new HashSet(mActivePageInfos.keySet());
4822            ArrayList versionedLanguagesEntryStates =
4823                getClosestVersionedEntryStates(entryState.getVersionID());
4824            Iterator versionedLanguagesEntryStateIter =
4825                versionedLanguagesEntryStates.iterator();
4826            while (versionedLanguagesEntryStateIter.hasNext()) {
4827                ContentObjectEntryState curEntryState = (
4828                    ContentObjectEntryState) versionedLanguagesEntryStateIter.
4829                    next();
4830                // let's remove the versioned language code to make the difference
4831
// with the active set.
4832
onlyActiveLanguageCodes.remove(curEntryState.getLanguageCode());
4833            }
4834
4835            // now that we have calculated the set of languages that must be
4836
// marked for deletion, let's do it baby :)
4837
Iterator onlyActiveLanguageIter = onlyActiveLanguageCodes.iterator();
4838            while (onlyActiveLanguageIter.hasNext()) {
4839                String JavaDoc curLanguageCode = (String JavaDoc) onlyActiveLanguageIter.next();
4840                this.markLanguageForDeletion(user, curLanguageCode,
4841                                             new
4842                                             RestoreVersionStateModificationContext(this.
4843                    getObjectKey(),
4844                    onlyActiveLanguageCodes, true, entryState));
4845            }
4846
4847            // now that we have marked for deletion the languages that only
4848
// exist in the present, let's go "back to the future" now and
4849
// restore all the languages for the version ID we are interested
4850
// in.
4851

4852            Iterator versionedEntryStatesIter = versionedLanguagesEntryStates.
4853                iterator();
4854            while (versionedEntryStatesIter.hasNext()) {
4855                ContentObjectEntryState curEntryState = (
4856                    ContentObjectEntryState) versionedEntryStatesIter.next();
4857                opResult.merge(super.restoreVersion(user, operationMode,
4858                    curEntryState, allowRemoveMoreRecentActive,
4859                    stateModificationContext));
4860            }
4861
4862            // need to recompute internal entry states map ?
4863
//this.rebuildStatusMaps();
4864

4865            /**
4866             * FIXME : why are we doing this ??? Some old issues ???
4867                         if ( (versionedPageInfo != null) &&
4868                  (versionedPageInfo.getPageType()==ContentPage.TYPE_DIRECT) ){
4869                // take care to keep the current parent page instead of the archived one
4870                Set entries = this.getActiveAndStagingEntryStates();
4871                Iterator iterator = entries.iterator();
4872                while ( iterator.hasNext() ){
4873                    ContentObjectEntryState curEntryState =
4874                        (ContentObjectEntryState)iterator.next();
4875                    if ( curEntryState.isStaging() ){
4876             JahiaPageInfo pageInfo = this.getPageInfoVersionIgnoreLanguage(
4877                            new EntryLoadRequest(curEntryState), true);
4878                        pageInfo.setParentID(currentParentId);
4879                        pageInfo.setAclID(currentAclId);
4880                    }
4881                }
4882                         }**/

4883
4884        }
4885        else {
4886            // no major shared-language change detected, let's just restore the
4887
// requested entry
4888
opResult.merge(super.restoreVersion(user, operationMode, entryState,
4889                                                allowRemoveMoreRecentActive,
4890                                                stateModificationContext));
4891        }
4892
4893        // now let's restore the page's parent data. In order to do this we must
4894
// also check on which languages we must work. In the case of a restore
4895
// of a move we must make sure we mark for deletion ALL the languages.
4896
if (versionedPageInfo != null &&
4897            versionedPageInfo.getPageType() == ContentPage.TYPE_DIRECT) {
4898
4899            /** @todo implement referring content restore */
4900            ArrayList locales = new ArrayList();
4901            locales.add(LanguageCodeConverters.languageCodeToLocale(entryState.
4902                getLanguageCode()));
4903            // here we don't bother with the staging entries since we will probably
4904
// be overwriting them...
4905
EntryLoadRequest loadRequest =
4906                new EntryLoadRequest(EntryLoadRequest.STAGING_WORKFLOW_STATE, 0,
4907                                     locales);
4908            ContentObject parentField = this.getParent(user, loadRequest,
4909                operationMode);
4910            if (parentField == null) {
4911                loadRequest = new EntryLoadRequest(EntryLoadRequest.
4912                    ACTIVE_WORKFLOW_STATE, 0, locales);
4913                parentField = this.getParent(user, loadRequest, operationMode);
4914            }
4915
4916            EntryLoadRequest versionedLoadRequest = null;
4917            if (!undeletePage) {
4918                versionedLoadRequest =
4919                    new EntryLoadRequest(EntryLoadRequest.
4920                                         VERSIONED_WORKFLOW_STATE,
4921                                         entryState.getVersionID(), locales);
4922            }
4923            else {
4924                versionedLoadRequest =
4925                    new EntryLoadRequest(EntryLoadRequest.
4926                                         VERSIONED_WORKFLOW_STATE,
4927                                         deleteVersionID, locales);
4928            }
4929            ContentObject versionedParentField = this.getParent(user,
4930                versionedLoadRequest, operationMode);
4931
4932            // first some quick sanity checks...
4933
boolean movedPage = false;
4934            if ( (parentField != null) && (versionedParentField != null)) {
4935                if (!parentField.getObjectKey().equals(versionedParentField.
4936                    getObjectKey())) {
4937                    movedPage = true;
4938                }
4939            }
4940
4941            Set languageCodes = new HashSet();
4942            languageCodes.add(entryState.getLanguageCode());
4943            languageCodes.add(ContentObject.SHARED_LANGUAGE);
4944
4945            if (movedPage) {
4946                // PAGE_MOVE_LOGIC
4947
// page was moved, change current page field to -1.
4948
( (ContentPageField) parentField).setValue( -1,
4949                    Jahia.getThreadParamBean());
4950                // @FIXME : is it wanted to delete the whole container on page move....
4951
// mark for delete the current parent container
4952
ContentObject currentParentContainer =
4953                        parentField.getParent(user, EntryLoadRequest.STAGED, operationMode);
4954                if ( currentParentContainer != null ){
4955                    currentParentContainer.markLanguageForDeletion(user,ContentObject.SHARED_LANGUAGE,
4956                        stateModificationContext);
4957                }
4958            }
4959
4960            // now we can finally restore the parent content
4961
if (versionedParentField != null) {
4962                // It is more usefull to have the start object the page
4963
opResult.merge(versionedParentField.restoreVersion(user,
4964                    operationMode, entryState, removeMoreRecentActive,
4965                    new RestoreVersionStateModificationContext(new
4966                    ContentPageKey(this.getID()),
4967                    languageCodes, false, entryState)));
4968
4969                // change page parent Acl accordingly to the new parent field acl
4970
this.getACL().setParentID(versionedParentField.getAclID());
4971
4972                ContentObject versionedParentContainer = versionedParentField.
4973                    getParent(user, versionedLoadRequest, operationMode);
4974
4975                if ( versionedParentContainer != null ){
4976                    if (versionedParentContainer.isDeletedOrDoesNotExist(entryState.
4977                            getVersionID())
4978                        &&
4979                        !versionedParentField.isDeletedOrDoesNotExist(entryState.getVersionID())) {
4980
4981                        // there are so much situation where a sub page is activated at v=t1, but not the parent container !!!!
4982
// It's the case, when a user has admin right for the page (subpage),
4983
// but not admin right on the parent container ( that is localted on the parent page ).
4984
// If we restore at v=t1, the subpage exist while the parent container will be deleted ( as it doesn't exist at v=t1 )!
4985
// This situation will create orphan pages ( pages that appear in sitemap but not in any container list )!!!!
4986
// That is why we should not restore the parent container
4987

4988                        // do not restore the parent container
4989

4990                    } else {
4991                        // It is more usefull to have the start object the page
4992
RestoreVersionStateModificationContext smc =
4993                            new RestoreVersionStateModificationContext(
4994                                new ContentPageKey(this.getID()),
4995                                    languageCodes, false, entryState, undeletePage);
4996                                    smc.setContainerPageChildId(this.getID());
4997                        opResult.merge(versionedParentContainer.restoreVersion(user,
4998                                operationMode, entryState, removeMoreRecentActive,
4999                                smc));
5000                    }
5001                }
5002            }
5003            else {
5004                logger.debug("Couldn't find parent field for page " +
5005                             this.getObjectKey() +
5006                             ", can't restore parent content...");
5007            }
5008        }
5009
5010        this.commitChanges(true);
5011
5012        // Invalidate sitemap
5013
ServicesRegistry.getInstance().getJahiaSiteMapService().resetSiteMap();
5014
5015        // check for cyclic situation
5016
int parentId = this.getParentID(EntryLoadRequest.STAGED);
5017        ContentPage parentPage;
5018        try {
5019            if (parentId > 0) {
5020                parentPage = ContentPage.getPage(parentId);
5021                if ( parentPage == null ){
5022                    // a corrupted situation
5023
this.setParentID(parentId,user,EntryLoadRequest.STAGED);
5024                } else if (parentPage != null &&
5025                        parentPage.getParentID(EntryLoadRequest.STAGED) == this.getID()) {
5026                    // cyclic situation !!!
5027
RestoreVersionStateModificationContext rsmc =
5028                            new RestoreVersionStateModificationContext(parentPage.getObjectKey(),
5029                                    stateModificationContext.getLanguageCodes(), false, entryState, stateModificationContext.isUndelete());
5030                    parentPage.restoreVersion(user, operationMode, entryState,
5031                            removeMoreRecentActive, false,
5032                            rsmc);
5033                }
5034            }
5035        } catch (Throwable JavaDoc t) {
5036            logger.warn(t, t);
5037        }
5038
5039        return opResult;
5040    }
5041
5042    /**
5043     * Is this kind of object shared (i.e. not one version for each language, but one version for every language)
5044     */

5045    public boolean isShared () {
5046        return false;
5047    }
5048
5049    private boolean remoteURLisDiff (String JavaDoc url1, String JavaDoc url2) {
5050        if (url1 == null && url2 == null) {
5051            return false;
5052        }
5053        if (url1 != null) {
5054            return (!url1.equals (url2));
5055        }
5056        return (!url2.equals (url1));
5057    }
5058
5059    private boolean hasArchivedPageInfos (String JavaDoc languageCode) {
5060        try {
5061            loadVersioningEntryStates ();
5062        } catch (JahiaException je) {
5063            logger.debug ("Exception loading versioning entries", je);
5064        }
5065
5066        if (languageCode == null) {
5067            return false;
5068        }
5069
5070        if (languageCode.equals (ContentObject.SHARED_LANGUAGE)
5071                && !this.mArchivedPageInfos.isEmpty ()) {
5072            return true;
5073        }
5074
5075        Iterator iterator = this.mArchivedPageInfos.iterator ();
5076        JahiaPageInfo pageInfo = null;
5077        while (iterator.hasNext ()) {
5078            pageInfo = (JahiaPageInfo) iterator.next ();
5079            if (pageInfo.getLanguageCode ().equals (languageCode)) {
5080                return true;
5081            }
5082        }
5083
5084        return false;
5085    }
5086
5087
5088    /**
5089     * Active staging child page links
5090     *
5091     * @param languageCodes Set
5092     * @param versioningActive boolean
5093     * @param saveVersion JahiaSaveVersion
5094     * @param user JahiaUser
5095     * @param jParams ParamBean
5096     * @param stateModifContext StateModificationContext
5097     * @throws JahiaException
5098     * @return ActivationTestResults
5099     */

5100    protected ActivationTestResults activeStagedLinkPages(
5101        Set languageCodes,
5102        boolean versioningActive,
5103        JahiaSaveVersion saveVersion,
5104        JahiaUser user,
5105        ParamBean jParams)
5106                    throws JahiaException {
5107
5108        ActivationTestResults result = new ActivationTestResults();
5109        if ( languageCodes == null) {
5110            return result;
5111        }
5112        Enumeration childPages = null;
5113        Iterator iterator = languageCodes.iterator();
5114        String JavaDoc languageCode = null;
5115        EntryLoadRequest loadRequest = null;
5116        ArrayList locales = null;
5117        StateModificationContext smc = null;
5118        while (iterator.hasNext()) {
5119            languageCode = (String JavaDoc) iterator.next();
5120            locales = new ArrayList();
5121            locales.add(org.jahia.utils.LanguageCodeConverters.languageCodeToLocale(languageCode));
5122            loadRequest = new EntryLoadRequest(EntryLoadRequest.STAGING_WORKFLOW_STATE,0,locales);
5123            loadRequest.setWithMarkedForDeletion(true);
5124
5125            // the following call also returns deleted content, we must not
5126
// try to activate deleted content !
5127
childPages = this.getContentPageChilds(user,LoadFlags.ALL,languageCode,false);
5128            while ( childPages.hasMoreElements() ){
5129                ContentPage childPage = (ContentPage)childPages.nextElement();
5130                if (childPage.hasActiveEntries() || childPage.hasStagingEntries()) {
5131                    if (childPage.getPageType(loadRequest) !=
5132                        ContentPage.TYPE_DIRECT) {
5133                        smc = new StateModificationContext(childPage.
5134                            getObjectKey(), languageCodes);
5135                        result.merge(childPage.activeStagingEntries(
5136                            languageCodes, versioningActive,
5137                            saveVersion, user, jParams, smc));
5138                    }
5139                } else {
5140                    // page is archived or deleted, we don't activate it.
5141
}
5142            }
5143        }
5144        return result;
5145    }
5146}
5147
Popular Tags