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}