Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/opencms/defaults/master/CmsMasterContent.java


1   /*
2   * File   : $Source: /usr/local/cvs/opencms/src/com/opencms/defaults/master/CmsMasterContent.java,v $
3   * Date   : $Date: 2003/04/14 06:35:59 $
4   * Version: $Revision: 1.28 $
5   *
6   * This library is part of OpenCms -
7   * the Open Source Content Mananagement System
8   *
9   * Copyright (C) 2001  The OpenCms Group
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about OpenCms, please see the
22  * OpenCms Website: http://www.opencms.org
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28  
29  package com.opencms.defaults.master;
30  
31  import com.opencms.core.A_OpenCms;
32  import com.opencms.core.CmsException;
33  import com.opencms.core.I_CmsConstants;
34  import com.opencms.defaults.A_CmsContentDefinition;
35  import com.opencms.defaults.I_CmsExtendedContentDefinition;
36  import com.opencms.defaults.master.genericsql.CmsDbAccess;
37  import com.opencms.file.CmsObject;
38  import com.opencms.file.CmsResource;
39  import com.opencms.file.CmsUser;
40  
41  import java.util.HashMap;
42  import java.util.StringTokenizer;
43  import java.util.Vector;
44  
45  /**
46   * This class is the master of several Modules. It carries a lot of generic
47   * data-fileds which can be used for a special Module.
48   *
49   * The module creates a set of methods to support project-integration, history
50   * and import - export.
51   *
52   * @author A. Schouten $
53   * $Revision: 1.28 $
54   * $Date: 2003/04/14 06:35:59 $
55   */
56  public abstract class CmsMasterContent
57      extends A_CmsContentDefinition
58      implements I_CmsExtendedContentDefinition {
59  
60      /** The cms-object to get access to the cms-ressources */
61      protected CmsObject m_cms = null;
62  
63      /** The dataset which holds all informations about this module */
64      protected CmsMasterDataSet m_dataSet = null;
65  
66      /** Is set to true, if the lockstate changes */
67      protected boolean m_lockstateWasChanged = false;
68  
69      /** A private HashMap to store all data access-objects. */
70      private static HashMap c_accessObjects = new HashMap();
71  
72      /** Vector of currently selected channels */
73      protected Vector m_selectedChannels = null;
74  
75      /** Vector of currently available channels */
76      protected Vector m_availableChannels = null;
77  
78      /**
79       * Registers a database access object for the contentdefinition type.
80       * @param subId the id-type of the contentdefinition.
81       * @param dBAccessObject the dBAccessObject that should be used to access
82       * the databse.
83       */
84      protected static void registerDbAccessObject(int subId, CmsDbAccess dBAccessObject) {
85          c_accessObjects.put(new Integer(subId), dBAccessObject);
86      }
87  
88      /**
89       * Returns a database access object for the contentdefinition type.
90       * @param subId the id-type of the contentdefinition.
91       * @return dBAccessObject the dBAccessObject that should be used to access
92       * the databse.
93       */
94      protected static CmsDbAccess getDbAccessObject(int subId) {
95          return (CmsDbAccess) c_accessObjects.get(new Integer(subId));
96      }
97  
98      /**
99       * Constructor to create a new contentdefinition. You can set data with your
100      * set-Methods. After you have called the write-method this definition gets
101      * a unique id.
102      */
103     public CmsMasterContent(CmsObject cms) {
104         m_cms = cms;
105         initValues();
106     }
107 
108     /**
109      * Constructor to create a new contentdefinition. You can set data with your
110      * set-Methods. After you have called the write-method this definition gets
111      * a unique id.
112      */
113     public CmsMasterContent(CmsObject cms, CmsMasterDataSet dataset) {
114         this(cms);
115         m_dataSet = dataset;
116     }
117 
118     /**
119      * Constructor to read a existing contentdefinition from the database. The
120      * data read from the databse will be filled into the member-variables.
121      * You can read them with the get- and modify them with the ser-methods.
122      * Changes you have made must be written back to the database by calling
123      * the write-method.
124      * @param cms the cms-object for access to cms-resources.
125      * @param id the master-id of the dataset to read.
126      * @throws CmsException if the data couldn't be read from the database.
127      */
128     public CmsMasterContent(CmsObject cms, Integer id) throws CmsException {
129         m_cms = cms;
130         initValues();
131         getDbAccessObject(getSubId()).read(m_cms, this, m_dataSet, id.intValue());
132     }
133     
134     /**
135      * TESTFIX (a.kandzior@alkacon.com) New code:
136      * Empty constructor needed for instanciating CDs as JavaBeans on JSPs.
137      */    
138     public CmsMasterContent() {}
139 
140     /**
141      * This method initialises all needed members with default-values.
142      */
143     protected void initValues() {
144         m_dataSet = new CmsMasterDataSet();
145         m_dataSet.m_masterId = I_CmsConstants.C_UNKNOWN_ID;
146         m_dataSet.m_subId = I_CmsConstants.C_UNKNOWN_ID;
147         m_dataSet.m_lockedBy = I_CmsConstants.C_UNKNOWN_ID;
148         m_dataSet.m_versionId = I_CmsConstants.C_UNKNOWN_ID;
149         m_dataSet.m_userName = null;
150         m_dataSet.m_groupName = null;
151         m_dataSet.m_lastModifiedByName = null;
152         m_dataSet.m_userId = I_CmsConstants.C_UNKNOWN_ID;
153         setAccessFlags(I_CmsConstants.C_ACCESS_DEFAULT_FLAGS);
154     }
155 
156     /**
157      * Returns the title of this cd
158      */
159     public String getTitle() {
160         return m_dataSet.m_title;
161     }
162 
163     /**
164      * Sets title of this cd
165      */
166     public void setTitle(String title) {
167         m_dataSet.m_title = title;
168     }
169 
170     /**
171      * Returns a Vector of media-objects for this master cd.
172      * @return a Vector of media-objects for this master cd.
173      * @throws CmsException if the media couldn't be read.
174      */
175     public Vector getMedia() throws CmsException {
176         if(m_dataSet.m_media == null) {
177             // the media was not read yet
178             // -> read them now from the db
179             m_dataSet.m_media = getDbAccessObject(getSubId()).readMedia(m_cms, this);
180         }
181         return m_dataSet.m_media;
182     }
183 
184     /**
185      * Registers a new media, that should be written by calling write().
186      * @param media - The mediaobject to register for writing.
187      */
188     public void addMedia(CmsMasterMedia media) {
189         m_dataSet.m_mediaToAdd.add(media);
190     }
191 
192     /**
193      * Registers a media for deletion.
194      * @param media - The mediaobject to register.
195      */
196     public void deleteMedia(CmsMasterMedia media) {
197         m_dataSet.m_mediaToDelete.add(media);
198     }
199 
200     /**
201      * Registers a media for update
202      * @param media - The mediaobject to register.
203      */
204     public void updateMedia(CmsMasterMedia media) {
205         m_dataSet.m_mediaToUpdate.add(media);
206     }
207 
208     /**
209      * Returns a Vector of channels for this master cd.
210      * @return a Vector of channel-names (String) for this master cd.
211      * @throws CmsException if the channel couldn't be read.
212      */
213     public Vector getChannels() throws CmsException {
214         if(m_dataSet.m_channel == null) {
215             // the channels was not read yet
216             // -> read them now from the db
217             m_dataSet.m_channel = getDbAccessObject(getSubId()).readChannels(m_cms, this);
218         }
219         return m_dataSet.m_channel;
220     }
221 
222     /**
223      * Registers a new channel, that should be written by calling write().
224      * @param channels - The channel to register for writing.
225      */
226     public void addChannel(String channel) {
227         m_dataSet.m_channelToAdd.add(channel);
228     }
229 
230     /**
231      * Registers a channel for deletion.
232      * @param channel - The channel to register for deleting.
233      */
234     public void deleteChannel(String channel) {
235         m_dataSet.m_channelToDelete.add(channel);
236     }
237 
238     /**
239      * delete method
240      * for delete instance of content definition
241      * @param cms the CmsObject to use.
242      */
243     public void delete(CmsObject cms) throws Exception {
244         getDbAccessObject(getSubId()).delete(m_cms, this, m_dataSet);
245     }
246 
247     /**
248      * change group method
249      * for the permissions of content definition
250      * @param cms the CmsObject to use.
251      * @param group the id of the new group.
252      */
253     public void chgrp(CmsObject cms, int group) throws Exception {
254         m_dataSet.m_groupId = group;
255         getDbAccessObject(getSubId()).changePermissions(m_cms, this, m_dataSet);
256     }
257 
258     /**
259      * change owner method
260      * for the permissions of content definition
261      * @param cms the CmsObject to use.
262      * @param owner the id of the new owner.
263      */
264     public void chown(CmsObject cms, int owner) throws Exception {
265         m_dataSet.m_userId = owner;
266         getDbAccessObject(getSubId()).changePermissions(m_cms, this, m_dataSet);
267     }
268 
269     /**
270      * change access flags method
271      * for the permissions of content definition
272      * @param cms the CmsObject to use.
273      * @param accessflags the new access flags.
274      */
275     public void chmod(CmsObject cms, int accessflags) throws Exception {
276         m_dataSet.m_accessFlags = accessflags;
277         getDbAccessObject(getSubId()).changePermissions(m_cms, this, m_dataSet);
278     }
279 
280     /**
281      * copy method
282      *
283      * @param cms the CmsObject to use.
284      * @return int The id of the new content definition
285      */
286     public int copy(CmsObject cms) throws Exception {
287         // insert the new cd with the copied dataset
288         return getDbAccessObject(getSubId()).copy(cms, this, (CmsMasterDataSet)m_dataSet.clone(), this.getMedia(), this.getChannels());
289     }
290 
291     /**
292      * write method
293      * to write the current content of the content definition to the database.
294      * @param cms the CmsObject to use.
295      */
296     public void write(CmsObject cms) throws CmsException {
297         // add or delete channels according to current selection
298         updateChannels();
299         // is this a new row or an existing row?
300         if(m_dataSet.m_masterId == I_CmsConstants.C_UNKNOWN_ID) {
301             // this is a new row - call the create statement
302             getDbAccessObject(getSubId()).insert(m_cms, this, m_dataSet);
303         } else {
304             // this is a existing row - call the write statement
305             if(m_lockstateWasChanged) {
306                 // update the locksyte
307                 getDbAccessObject(getSubId()).writeLockstate(m_cms, this, m_dataSet);
308             } else {
309                 // write the changes to the database
310                 getDbAccessObject(getSubId()).write(m_cms, this, m_dataSet);
311             }
312         }
313         // everything is written - so lockstate was updated
314         m_lockstateWasChanged = false;
315         // for next access to the media - clean them so they must be read again
316         // from the db
317         m_dataSet.m_media = null;
318         m_dataSet.m_mediaToAdd = new Vector();
319         m_dataSet.m_mediaToDelete = new Vector();
320         m_dataSet.m_mediaToUpdate = new Vector();
321 
322         // for next access to the channels - clean them so they must be read again
323         // from the db
324         m_dataSet.m_channel = null;
325         m_dataSet.m_channelToAdd = new Vector();
326         m_dataSet.m_channelToDelete = new Vector();
327     }
328 
329     /**
330      * import method
331      * to import the current content of the content definition to the database.
332      */
333     public void importMaster() throws Exception {
334         getDbAccessObject(getSubId()).insert(m_cms, this, m_dataSet);
335         // everything is written - so lockstate was updated
336         m_lockstateWasChanged = false;
337         // for next access to the media - clean them so they must be read again
338         // from the db
339         m_dataSet.m_media = null;
340         m_dataSet.m_mediaToAdd = new Vector();
341         m_dataSet.m_mediaToDelete = new Vector();
342         m_dataSet.m_mediaToUpdate = new Vector();
343 
344         // for next access to the channels - clean them so they must be read again
345         // from the db
346         m_dataSet.m_channel = null;
347         m_dataSet.m_channelToAdd = new Vector();
348         m_dataSet.m_channelToDelete = new Vector();
349     }
350 
351     /**
352      * gets the unique Id of a content definition instance
353      * @param cms the CmsObject to use.
354      * @return a string with the Id
355      */
356     public String getUniqueId(CmsObject cms) {
357         return getId() + "";
358     }
359 
360     /**
361      * gets the unique Id of a content definition instance
362      * @param cms the CmsObject to use.
363      * @return a int with the Id
364      */
365     public int getId() {
366         return m_dataSet.m_masterId;
367     }
368 
369     /**
370      * Gets the lockstate.
371      * @return a int with the user who has locked the ressource.
372      */
373     public int getLockstate() {
374         int retValue = -2; // no writeaccess for this user
375         try {
376             if(hasWriteAccess(m_cms)) {
377                 retValue = m_dataSet.m_lockedBy;
378             }
379         } catch(CmsException exc) {
380             // ignore this exception - no writeaccess
381         }
382         return retValue;
383     }
384 
385     /**
386      * Sets the lockstates
387      * @param the lockstate for the actual entry.
388      */
389     public void setLockstate(int lockstate) {
390         m_lockstateWasChanged = true;
391         m_dataSet.m_lockedBy = lockstate;
392     }
393 
394     /**
395      * Gets the owner of this contentdefinition.
396      */
397     public int getOwner() {
398         return m_dataSet.m_userId;
399     }
400 
401     /**
402      * Gets the ownername
403      */
404     public String getOwnerName() {
405         String retValue = m_dataSet.m_userId + "";
406         if(m_dataSet.m_userName == null || "".equals(m_dataSet.m_userName.trim())) {
407             try { // to read the real name of this user
408                 retValue = m_cms.readUser(m_dataSet.m_userId).getName();
409             } catch(CmsException exc) {
410                 // ignore the exception - it was not possible to read the group
411                 // instead return the groupid
412             }
413         } else {
414             // this is a history value - return it
415             retValue = m_dataSet.m_userName;
416         }
417         return retValue;
418     }
419 
420     /**
421      * Sets the owner of this contentdefinition.
422      */
423     public void setOwner(int id) {
424         m_dataSet.m_userId = id;
425     }
426 
427     /**
428      * Gets the groupname
429      */
430     public String getGroup() {
431         String retValue = m_dataSet.m_groupId + "";
432         if(m_dataSet.m_groupName == null || "".equals(m_dataSet.m_groupName.trim())) {
433             try { // to read the real name of this group
434                 retValue = m_cms.readGroup(m_dataSet.m_groupId).getName();
435             } catch(CmsException exc) {
436                 // ignore the exception - it was not possible to read the group
437                 // instead return the groupid
438             }
439         } else {
440             // this is historical data - return it
441             retValue = m_dataSet.m_groupName;
442         }
443         return retValue;
444     }
445 
446     /**
447      * Gets the groupid
448      */
449     public int getGroupId() {
450         return m_dataSet.m_groupId;
451     }
452 
453     /**
454      * Sets the group.
455      */
456     public void setGroup(int id) {
457         m_dataSet.m_groupId = id;
458     }
459 
460     /**
461      * Returns the projectId of the content definition.
462      * If the cd belongs to the current project the value
463      * is the id of the current project otherwise its
464      * the id of the online project
465      *
466      * @return int The project id
467      */
468     public int getProjectId() {
469         return m_dataSet.m_projectId;
470     }
471 
472     /**
473      * Returns the state of the content definition:
474      * unchanged, new, changed or deleted
475      *
476      * @return int The state of the cd
477      */
478     public int getState() {
479         return m_dataSet.m_state;
480     }
481 
482     /**
483      * Returns the projectId of the content definition
484      * that is stored in the cd table after the cd
485      * was locked
486      *
487      * @return int The id of the cd
488      */
489     public int getLockedInProject() {
490         return m_dataSet.m_lockedInProject;
491     }
492 
493     /**
494      * Returns the sub-id of this contentdefinition. You have to implement this
495      * method so it returns a unique sunb-id that describes the type of the
496      * contentdefinition. (E.g. article: sub-id=1; table: sub-id=2).
497      */
498     abstract public int getSubId();
499 
500     /**
501      * Returns a String representation of this instance.
502      * This can be used for debugging purposes.
503      */
504     public String toString() {
505         StringBuffer returnValue = new StringBuffer();
506         returnValue.append(this.getClass().getName() + "{");
507         returnValue.append("UniqueId=" + getUniqueId(m_cms) + ";");
508         returnValue.append("Lockstate=" + getLockstate() + ";");
509         returnValue.append("AccessFlags=" + getAccessFlagsAsString() + ";");
510         returnValue.append(m_dataSet.toString() + "}");
511         return returnValue.toString();
512     }
513 
514     /**
515      * set the accessFlag for the CD
516      * @param the accessFlag
517      */
518     public void setAccessFlags(int accessFlags) {
519         m_dataSet.m_accessFlags = accessFlags;
520     }
521 
522     /**
523      * get the accessFlag for the CD
524      * @return the accessFlag
525      */
526     public int getAccessFlags() {
527         return m_dataSet.m_accessFlags;
528     }
529 
530     /**
531      * Convenience method to get the access-Flags as String representation.
532      * @return String of access rights
533      */
534     public String getAccessFlagsAsString() {
535         int accessFlags = getAccessFlags();
536         String str = "";
537         str += ((accessFlags & I_CmsConstants.C_ACCESS_OWNER_READ)>0?"r":"-");
538         str += ((accessFlags & I_CmsConstants.C_ACCESS_OWNER_WRITE)>0?"w":"-");
539         str += ((accessFlags & I_CmsConstants.C_ACCESS_OWNER_VISIBLE)>0?"v":"-");
540         str += ((accessFlags & I_CmsConstants.C_ACCESS_GROUP_READ)>0?"r":"-");
541         str += ((accessFlags & I_CmsConstants.C_ACCESS_GROUP_WRITE)>0?"w":"-");
542         str += ((accessFlags & I_CmsConstants.C_ACCESS_GROUP_VISIBLE)>0?"v":"-");
543         str += ((accessFlags & I_CmsConstants.C_ACCESS_PUBLIC_READ)>0?"r":"-");
544         str += ((accessFlags & I_CmsConstants.C_ACCESS_PUBLIC_WRITE)>0?"w":"-");
545         str += ((accessFlags & I_CmsConstants.C_ACCESS_PUBLIC_VISIBLE)>0?"v":"-");
546         str += ((accessFlags & I_CmsConstants.C_ACCESS_INTERNAL_READ)>0?"i":"-");
547         return str;
548     }
549 
550     /**
551      * has the current user the right to view the CD
552      * @return true if this cd is visible
553      */
554     public boolean isVisible() {
555         CmsUser currentUser = m_cms.getRequestContext().currentUser();
556         try {
557             if(m_cms.isAdmin()) {
558                 return true;
559             } else {
560                 if ( !accessOther(C_ACCESS_PUBLIC_VISIBLE)
561                     && !accessOwner(m_cms, currentUser, C_ACCESS_OWNER_VISIBLE)
562                     && !accessGroup(m_cms, currentUser, C_ACCESS_GROUP_VISIBLE)) {
563                     return false;
564                 } else {
565                     return true;
566                 }
567             }
568         } catch(CmsException exc) {
569             // no access to cms -> not visible
570             return false;
571         }
572     }
573 
574     /**
575      * returns true if the CD is readable for the current user
576      * @return true if the cd is readable
577      */
578     public boolean isReadable() {
579         try {
580             if(m_cms.isAdmin()) {
581                 return true;
582             } else {
583                 return hasReadAccess(m_cms);
584             }
585         } catch(CmsException exc) {
586             // there was a cms-exception - no read-access!
587             return false;
588         }
589     }
590 
591     /**
592      * returns true if the CD is writeable for the current user
593      * @return true if the cd is writeable
594      */
595     public boolean isWriteable() {
596         try {
597             if(m_cms.isAdmin()) {
598                 return true;
599             } else {
600                 return this.hasWriteAccess(m_cms);
601             }
602         } catch(CmsException exc) {
603             // there was a cms-exception - no write-access!
604             return false;
605         }
606     }
607 
608     /**
609      * Publishes the content definition directly
610      *
611      * @param cms The CmsObject
612      */
613     public void publishResource(CmsObject cms) throws Exception {
614         Vector changedResources = new Vector();
615         Vector changedModuleData = new Vector();
616         int versionId = 0;
617         long publishDate = System.currentTimeMillis();
618         boolean enableHistory = cms.isHistoryEnabled();
619         if (enableHistory){
620             // Get the next version id
621             versionId = cms.getBackupVersionId();
622             // backup the current project
623             cms.backupProject(cms.getRequestContext().currentProject().getId(), versionId, publishDate);
624         }
625         // now publish the content definition
626         getDbAccessObject(getSubId()).publishResource(cms, m_dataSet, getSubId(), this.getClass().getName(),
627         enableHistory, versionId, publishDate, changedResources, changedModuleData);
628         // update the cache
629         cms.getOnlineElementCache().cleanupCache(changedResources, changedModuleData);
630         A_OpenCms.fireCmsEvent(cms, com.opencms.flex.I_CmsEventListener.EVENT_PUBLISH_BO_RESOURCE, new HashMap(0));
631     }
632 
633     /**
634      * Undelete method
635      * for undelete instance of content definition
636      *
637      * @param cms The CmsObject
638      */
639     public void undelete(CmsObject cms) throws Exception {
640         getDbAccessObject(getSubId()).undelete(m_cms, this, m_dataSet);
641     }
642     
643     /**
644      * Overwrite this method in your subclasses to execute any tasks before the resources are published.
645      */
646     public static boolean beforePublish( CmsObject cms, Boolean enableHistory,
647         Integer projectId, Integer versionId, Long publishingDate,
648         Vector changedRessources, Vector changedModuleData, CmsMasterDataSet dataset ) {
649         
650         if (false && ((cms == null) && (enableHistory == null) && (projectId == null) &&
651             (versionId == null) && (publishingDate == null) && (changedRessources == null) &&
652             (changedModuleData == null) && (dataset == null))) {
653             // silly test so that eclipse does not complain about unused method parameters
654         }
655         
656         return true;
657     }
658 
659     /**
660      * Publishes all modified content definitions for this project.
661      * @param cms The CmsObject
662      * @param enableHistory set to true if backup tables should be filled.
663      * @param projectId the Project that should be published.
664      * @param versionId the versionId to save in the backup tables.
665      * @param publishingDate the date and time of this publishing process.
666      * @param subId the subId to publish cd's for.
667      * @param contentDefinitionClassName the name of cd-class.
668      * @param changedRessources a Vector of Ressources that were changed by this
669      * publishing process.
670      * @param changedModuleData a Vector of Ressource that were changed by this
671      * publishing process. New published data will be add to this Vector to
672      * return it.
673      */
674     protected static void publishProject(CmsObject cms, boolean enableHistory,
675         int projectId, int versionId, long publishingDate, int subId,
676         String contentDefinitionClassName, Vector changedRessources,
677         Vector changedModuleData) throws CmsException {
678 
679          // now publish the project
680          getDbAccessObject(subId).publishProject(cms, enableHistory, projectId,
681              versionId, publishingDate, subId, contentDefinitionClassName,
682              changedRessources, changedModuleData );
683     }
684 
685     /**
686      * Returns a Vector with the datasets of the contentdefinitions in the given channel.
687      * @param subId the id-type of the contentdefinition.
688      * @param channelId the id of the channel.
689      * @return Vector the vector that includes the datasets
690      */
691     protected static Vector readAllByChannel(CmsObject cms, int channelId, int subId) throws CmsException{
692         return getDbAccessObject(subId).readAllByChannel(cms, channelId, subId);
693     }
694 
695     /**
696      * Returns the date of the last modification of the content definition
697      *
698      * @return long The date of the last modification
699      */
700     public long getDateLastModified() {
701         return m_dataSet.m_dateLastModified;
702     }
703 
704     /**
705      * Returns the date of the creation of the content definition
706      *
707      * @return long The date of the creation
708      */
709     public long getDateCreated() {
710         return m_dataSet.m_dateCreated;
711     }
712 
713     /**
714      * Returns the id of the user who has modified the content definition
715      *
716      * @return int The id of the user who has modified the cd
717      */
718     public int getLastModifiedBy() {
719         return m_dataSet.m_lastModifiedBy;
720     }
721 
722     /**
723      * Returns the name of the user who has modified the content definition
724      *
725      * @return String The name of the user who has modified the cd
726      */
727     public String getLastModifiedByName() {
728         String retValue = m_dataSet.m_lastModifiedBy + "";;
729         if(m_dataSet.m_lastModifiedByName == null) {
730             try {
731                 retValue = m_cms.readUser(m_dataSet.m_lastModifiedBy).getName();
732             } catch(CmsException exc) {
733                 // ignore this exception, return the id instead
734             }
735         } else {
736             retValue = m_dataSet.m_lastModifiedByName;
737         }
738         return retValue;
739     }
740 
741     /**
742      * Returns the id of the version in the history of the content definition
743      *
744      * @return int The id of the version, or -1 if there is no version-info
745      */
746     public int getVersionId() {
747         return m_dataSet.m_versionId;
748     }
749 
750     /**
751      * Restore method
752      * for restore instance of content definition from the history
753      *
754      * @param cms The CmsObject
755      * @param versionId The id of the version to restore
756      */
757     public void restore(CmsObject cms, int versionId) throws Exception {
758         getDbAccessObject(this.getSubId()).restore(cms, this, m_dataSet, versionId);
759     }
760 
761     /**
762      * History method
763      * returns the vector of the versions of content definition in the history
764      *
765      * @param cms The CmsObject
766      * @return Vector The versions of the cd in the history
767      */
768     public Vector getHistory(CmsObject cms) throws Exception {
769         return getDbAccessObject(this.getSubId()).getHistory(cms, this.getClass(), m_dataSet.m_masterId, this.getSubId());
770     }
771 
772     /**
773      * History method
774      * returns the cd of the version with the given versionId
775      *
776      * @param cms The CmsObject
777      * @param versionId The version id
778      * @return Object The object with the version of the cd
779      */
780     public Object getVersionFromHistory(CmsObject cms, int versionId) throws Exception{
781         return getDbAccessObject(this.getSubId()).getVersionFromHistory(cms, this.getClass(), m_dataSet.m_masterId, this.getSubId(), versionId);
782     }
783 
784 
785     /**
786      * Get all currently selected channels
787      * @return Vector of all currently selected channels
788      */
789      public Vector getSelectedChannels() throws CmsException{
790         if (m_selectedChannels == null) {
791             Vector dbChannels = getChannels();
792             m_selectedChannels = new Vector();
793             String rootChannel = getDbAccessObject(this.getSubId()).getRootChannel();
794             int offset = rootChannel.length()-1;
795             for (int i=0; i< dbChannels.size(); i++) {
796                 // remove the root channel name from the channel's name
797                 // and add to new Vector
798                 m_selectedChannels.add(((String)dbChannels.elementAt(i)).substring(offset));
799             }
800         }
801         return m_selectedChannels;
802      }
803 
804      /**
805      * set Selected Channels
806      * @param channels a String containing the channels names as a comma separated list
807      */
808     public void setSelectedChannels(String channels) {
809         StringTokenizer tk = new StringTokenizer(channels, ",");
810         Vector v = new Vector();
811         int tokens = tk.countTokens();
812         if (channels != null && channels.equals("empty")) {
813             m_selectedChannels = v;
814         }else if (tokens > 0) {
815             for (int i=0; i<tokens; i++) {
816                 v.addElement(tk.nextToken());
817             }
818             m_selectedChannels = v;
819         }
820     }
821 
822      /**
823       * Get all currently available channels
824       * Note: the root channel of the module is not included in the returned
825       * channelnames. For example if the root channel is /Jobs/ and a channel's
826       * name is /Jobs/Education/Cologne/ the returned name for this channel will
827       * be /Education/Cologne/.
828       * @param cms object to access system resources
829       * @return a Vector of all channels that can be selected
830       */
831       public Vector getAvailableChannels(CmsObject cms) throws CmsException {
832         if (m_availableChannels == null) {
833             Vector selectedChannels = getSelectedChannels();
834             Vector subChannels = getAllSubChannelsOfRootChannel(cms);
835             for (int i=0; i<subChannels.size(); i++) {
836                 for (int j=0; j<selectedChannels.size(); j++) {
837                     if (subChannels.elementAt(i).equals(selectedChannels.elementAt(j))) {
838                         subChannels.removeElementAt(i);
839                         i--;
840                         break;
841                     }
842                 }
843             }
844             m_availableChannels = subChannels;
845         }
846         return m_availableChannels;
847       }
848 
849     /**
850      * Set the Available Channels
851      * @param channels a String containing the channels to add as a comma separated list
852      */
853     public void setAvailableChannels(String channels) {
854         StringTokenizer tk = new StringTokenizer(channels, ",");
855         Vector v = new Vector();
856         int tokens = tk.countTokens();
857         if (channels != null && channels.equals("empty")) {
858             m_availableChannels = v;
859         } else if (tokens > 0) {
860             for (int i=0; i<tokens; i++) {
861                 v.addElement(tk.nextToken());
862             }
863             m_availableChannels = v;
864         }
865     }
866 
867     /**
868      * Get all subchannels of a channel.
869      * Method returns only channels that doesn't have further subchannels because
870      * it is it not intended to add contentdefinitions to channels that are not
871      * endpoints of the channel folder structure. If different functionality
872      * is needed this method has to be overridden in derived
873      * contentdefinition classes.
874      * @param cms object to access system resources
875      * @param channel channel to be searched for subchannels
876      * @return Vector with names of all subchannels
877      * @throws com.opencms.core.CmsException in case of unrecoverable errors
878      */
879     public static Vector getAllSubChannelsOf (CmsObject cms, String channel)
880             throws CmsException {
881         Vector allChannels = new Vector();
882         Vector subChannels = cms.getResourcesInFolder("//cos" + channel);
883         for (int i=0; i < subChannels.size(); i++) {
884             CmsResource resource = (CmsResource)subChannels.get(i);
885             if (resource.getState() != CmsResource.C_STATE_DELETED) {            
886                 String folder = resource.getAbsolutePath();
887                 Vector v = getAllSubChannelsOf(cms, folder);
888                 if (v.size() == 0 && hasWriteAccess(cms, resource)) {
889                     allChannels.add(folder);
890                 }else {
891                     for (int j=0; j < v.size(); j++) {
892                         allChannels.add(v.get(j));
893                     }
894                 }
895             }
896         }
897         return allChannels;
898     }
899 
900 
901     /**
902      * Get all subchannels of the module root channel without the root channel in the channel names
903      * Method returns only channels that doesn't have further subchannels because
904      * it is it not intended to add contentdefinitions to channels that are not
905      * endpoints in the channel folder structure. If different functionality
906      * is needed this method has to be overridden in derived
907      * contentdefinition classes.
908      * @param cms object to access system resources
909      * @param channel channel to be searched for subchannels
910      * @return Vector with names of all subchannels
911      * @throws com.opencms.core.CmsException in case of unrecoverable errors
912      */
913     public Vector getAllSubChannelsOfRootChannel (CmsObject cms)
914             throws CmsException {
915         Vector allChannels = new Vector();
916         String rootChannel = getDbAccessObject(this.getSubId()).getRootChannel();
917         Vector subChannels = cms.getResourcesInFolder("//cos" + rootChannel);
918         int offset = rootChannel.length()-1;
919         for (int i=0; i < subChannels.size(); i++) {
920             CmsResource resource = (CmsResource)subChannels.get(i);
921             if (resource.getState() != CmsResource.C_STATE_DELETED) {
922                 String folder = resource.getAbsolutePath();
923                 Vector v = getAllSubChannelsOf(cms, folder);
924                 if (v.size() == 0 && hasWriteAccess(cms, resource)) {
925                     allChannels.add(folder.substring(offset));
926                 } else {
927                     for (int j=0; j < v.size(); j++) {
928                         allChannels.add(((String)v.get(j)).substring(offset));
929                     }
930                 }
931             }
932         }
933         return allChannels;
934     }
935 
936     /**
937      * Add or remove channels
938      * compares the currently selected channels with the selected
939      * channels stored in the database and adds or deletes channels if necessary
940      */
941     protected void updateChannels() throws CmsException{
942         Vector dbChannels = getChannels();
943         Vector selectedChannels = getSelectedChannels();
944         String rootChannel = getDbAccessObject(this.getSubId()).getRootChannel();
945         String prefix = rootChannel.substring(0, rootChannel.length()-1);
946         // mark all channels to be deleted if not existing in m_selectedChannels but in datatabase
947         for (int i=0; i < dbChannels.size(); i++) {
948             boolean found = false;
949             for (int j=0; j < selectedChannels.size(); j++) {
950                 if (dbChannels.elementAt(i).equals(prefix + ((String)selectedChannels.elementAt(j)))) {
951                     found = true;
952                     break;
953                 }
954             }
955             if (!found) {
956                 deleteChannel((String)dbChannels.elementAt(i));
957             }
958         }
959         // mark all channels to be added if existing in m_selectedChannels but not in database
960         for (int i=0; i < selectedChannels.size(); i++) {
961             boolean found = false;
962             for (int j=0; j < dbChannels.size(); j++) {
963                 if ((prefix + ((String)selectedChannels.elementAt(i))).equals(dbChannels.elementAt(j))) {
964                     found = true;
965                     break;
966                 }
967             }
968             if (!found) {
969                 addChannel(prefix + (String)selectedChannels.elementAt(i));
970             }
971         }
972     }
973 
974     /**
975      * Get the root channel of the module
976      * @return the root channel of the module
977      */
978      public String getRootChannel() {
979         return getDbAccessObject(this.getSubId()).getRootChannel();
980      }
981 
982     /**
983      * has the current user the right to write the resource
984      * @return a boolean
985      */
986     protected static boolean hasWriteAccess(CmsObject cms, CmsResource resource) throws CmsException {
987         CmsUser currentUser = cms.getRequestContext().currentUser();
988 
989         // check the rights for the current resource
990         if( ! ( accessOther(C_ACCESS_PUBLIC_WRITE, resource) ||
991                 accessOwner(cms, currentUser, C_ACCESS_OWNER_WRITE, resource) ||
992                 accessGroup(cms, currentUser, C_ACCESS_GROUP_WRITE, resource) ) ) {
993             // no write access to this resource!
994             return false;
995         }
996         return true;
997     }
998 
999     /**
1000     * Checks, if the owner may access this resource.
1001     *
1002     * @param cms the cmsObject
1003     * @param currentUser The user who requested this method.
1004     * @param currentProject The current project of the user.
1005     * @param flags The flags to check.
1006     *
1007     * @return wether the user has access, or not.
1008     */
1009    protected static boolean accessOwner(CmsObject cms, CmsUser currentUser,
1010                                    int flags, CmsResource resource) throws CmsException {
1011        // The Admin has always access
1012        if( cms.isAdmin() ) {
1013            return(true);
1014        }
1015        // is the resource owned by this user?
1016        if(resource.getOwnerId() == currentUser.getId()) {
1017            if( (resource.getAccessFlags() & flags) == flags ) {
1018                return true ;
1019            }
1020        }
1021        // the resource isn't accesible by the user.
1022        return false;
1023    }
1024
1025    /**
1026     * Checks, if the group may access this resource.
1027     *
1028     * @param cms the cmsObject
1029     * @param currentUser The user who requested this method.
1030     * @param currentProject The current project of the user.
1031     * @param flags The flags to check.
1032     *
1033     * @return wether the user has access, or not.
1034     */
1035    protected static boolean accessGroup(CmsObject cms, CmsUser currentUser,
1036                                  int flags, CmsResource resource) throws CmsException {
1037        // is the user in the group for the resource?
1038        if(cms.userInGroup(currentUser.getName(), cms.readGroup(resource.getGroupId()).getName())) {
1039            if( (resource.getAccessFlags() & flags) == flags ) {
1040                return true;
1041            }
1042        }
1043        // the resource isn't accesible by the user.
1044        return false;
1045    }
1046
1047    /**
1048     * Checks, if others may access this resource.
1049     *
1050     * @param currentUser The user who requested this method.
1051     * @param currentProject The current project of the user.
1052     * @param flags The flags to check.
1053     *
1054     * @return wether the user has access, or not.
1055     */
1056    protected static boolean accessOther( int flags, CmsResource resource) throws CmsException {
1057        if ((resource.getAccessFlags() & flags) == flags) {
1058            return true;
1059        } else {
1060            return false;
1061        }
1062    }
1063}