001: package org.tigris.scarab.om;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2005 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: // JDK classes
050: import com.workingdogs.village.DataSetException;
051: import java.io.Serializable;
052: import java.util.Comparator;
053: import java.util.Iterator;
054: import java.util.List;
055: import java.util.ArrayList;
056: import java.util.Collections;
057:
058: // Commons classes
059: import org.apache.commons.lang.StringUtils;
060:
061: // Turbine classes
062: import org.apache.torque.TorqueException;
063: import org.apache.torque.om.Persistent;
064: import org.apache.torque.util.Criteria;
065: import org.apache.torque.util.SqlEnum;
066:
067: import java.sql.Connection;
068: import org.apache.fulcrum.security.TurbineSecurity;
069: import org.apache.fulcrum.security.util.DataBackendException;
070: import org.apache.fulcrum.security.util.RoleSet;
071: import org.apache.fulcrum.security.util.TurbineSecurityException;
072: import org.apache.fulcrum.security.util.UnknownEntityException;
073: import org.apache.fulcrum.security.entity.User;
074: import org.apache.fulcrum.security.entity.Group;
075: import org.apache.fulcrum.security.entity.Role;
076:
077: // Scarab classes
078: import org.tigris.scarab.om.Module;
079: import org.tigris.scarab.om.MITList;
080: import org.tigris.scarab.om.ScarabUserManager;
081: import org.tigris.scarab.tools.localization.L10NKey;
082: import org.tigris.scarab.tools.localization.L10NKeySet;
083: import org.tigris.scarab.util.ScarabConstants;
084: import org.tigris.scarab.util.ScarabException;
085: import org.tigris.scarab.util.ScarabPaginatedList;
086: import org.tigris.scarab.util.ScarabLocalizedTorqueException;
087: import org.tigris.scarab.util.ScarabLocalizedTurbineSecurityException;
088: import org.tigris.scarab.services.cache.ScarabCache;
089: import org.tigris.scarab.services.security.ScarabSecurity;
090:
091: // FIXME! do not like referencing servlet inside of business objects
092: // though I have forgotten how I might avoid it
093: import org.apache.turbine.Turbine;
094: import org.apache.fulcrum.security.impl.db.entity.TurbinePermissionPeer;
095: import org.apache.fulcrum.security.impl.db.entity.TurbineUserGroupRolePeer;
096: import org.apache.fulcrum.security.impl.db.entity.TurbineRolePermissionPeer;
097: import org.apache.fulcrum.security.impl.db.entity.TurbineUserPeer;
098: import org.tigris.scarab.util.ScarabRuntimeException;
099:
100: /**
101: * The ScarabModule class is the focal point for dealing with
102: * Modules. It implements the concept of a Module which is a
103: * single module and is the base interface for all Modules. In code,
104: * one should <strong>never reference ScarabModule directly</strong>
105: * -- use its Module interface instead. This allows us to swap
106: * out Module implementations by modifying the Scarab.properties
107: * file.
108: *
109: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
110: * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
111: * @version $Id: ScarabModule.java 10198 2006-07-03 23:33:30Z dabbous $
112: */
113: public class ScarabModule extends BaseScarabModule implements
114: Persistent, Module, Group {
115: private static final String GET_USERS = "getUsers";
116:
117: protected static final Integer ROOT_ID = new Integer(0);
118: private static final String PROJECT_OWNER_ROLE = "Project Owner";
119: private String httpDomain = null;
120: private String instanceId = null;
121: private String port = null;
122: private String scheme = null;
123: private String scriptName = null;
124:
125: /**
126: * Get the value of domain.
127: * @return value of domain.
128: */
129: public String getHttpDomain() {
130: if (httpDomain == null || httpDomain.length() == 0) {
131: try {
132: httpDomain = GlobalParameterManager
133: .getString(ScarabConstants.HTTP_DOMAIN);
134: } catch (Exception e) {
135: getLog().error("Error getting HTTP_DOMAIN:", e);
136: }
137: }
138: return httpDomain;
139: }
140:
141: /**
142: * Set the value of domain.
143: * @param v Value to assign to domain.
144: */
145: public void setHttpDomain(String v) {
146: if (v != null) {
147: this .httpDomain = v;
148: }
149: }
150:
151: /**
152: * Get the value of the Scarab instance id.
153: * @return value of domain.
154: */
155: public String getScarabInstanceId() {
156: if (instanceId == null || instanceId.length() == 0) {
157: try {
158: instanceId = GlobalParameterManager
159: .getString(ScarabConstants.INSTANCE_ID);
160: } catch (Exception e) {
161: getLog().error("Error getting DOMAIN_NAME:", e);
162: }
163: }
164: return instanceId;
165: }
166:
167: /**
168: * Set the value of Scarab domain name.
169: * The value can be an arbirtrary String.
170: * Note: This instance attriute is NOT related to ip/email-domains!
171: * @param v Value to assign to domain.
172: */
173: public void setScarabInstanceId(String v) {
174: if (v != null) {
175: this .instanceId = v;
176: }
177: }
178:
179: /**
180: * Get the value of port.
181: * @return value of port.
182: */
183: public String getPort() throws TorqueException {
184: if (port == null) {
185: port = GlobalParameterManager
186: .getString(ScarabConstants.HTTP_PORT);
187: }
188: return port;
189: }
190:
191: /**
192: * Set the value of port.
193: * @param v Value to assign to port.
194: */
195: public void setPort(String v) throws TorqueException {
196: if (v != null) {
197: this .port = v;
198: }
199: }
200:
201: /**
202: * Get the value of scheme.
203: * @return value of scheme.
204: */
205: public String getScheme() throws TorqueException {
206: if (scheme == null) {
207: scheme = GlobalParameterManager
208: .getString(ScarabConstants.HTTP_SCHEME);
209: }
210: return scheme;
211: }
212:
213: /**
214: * Set the value of scheme.
215: * @param v Value to assign to scheme.
216: */
217: public void setScheme(String v) throws TorqueException {
218: if (v != null) {
219: this .scheme = v;
220: }
221: }
222:
223: /**
224: * Get the value of scriptName.
225: * @return value of scriptName.
226: */
227: public String getScriptName() throws TorqueException {
228: if (scriptName == null) {
229: scriptName = GlobalParameterManager
230: .getString(ScarabConstants.HTTP_SCRIPT_NAME);
231: }
232: return scriptName;
233: }
234:
235: /**
236: * Set the value of scriptName.
237: * @param v Value to assign to scriptName.
238: */
239: public void setScriptName(String v) throws TorqueException {
240: if (v != null) {
241: this .scriptName = v;
242: }
243: }
244:
245: /**
246: * @see org.tigris.scarab.om.Module#getUsers(String)
247: */
248: public ScarabUser[] getUsers(String permission) {
249: List perms = new ArrayList(1);
250: perms.add(permission);
251: return getUsers(perms);
252: }
253:
254: /**
255: * @see org.tigris.scarab.om.Module#getUsers(List)
256: */
257: public ScarabUser[] getUsers(List permissions) {
258: ScarabUser[] result = null;
259: Object obj = ScarabCache.get(this , GET_USERS,
260: (Serializable) permissions);
261: if (obj == null) {
262: Criteria crit = new Criteria();
263: crit.setDistinct();
264: if (permissions.size() == 1) {
265: crit
266: .add(TurbinePermissionPeer.NAME, permissions
267: .get(0));
268: } else if (permissions.size() > 1) {
269: crit.addIn(TurbinePermissionPeer.NAME, permissions);
270: }
271:
272: if (permissions.size() >= 1) {
273: ArrayList groups = new ArrayList(2);
274: groups.add(getModuleId());
275: groups.add(ROOT_ID);
276: crit.addJoin(TurbinePermissionPeer.PERMISSION_ID,
277: TurbineRolePermissionPeer.PERMISSION_ID);
278: crit.addJoin(TurbineRolePermissionPeer.ROLE_ID,
279: TurbineUserGroupRolePeer.ROLE_ID);
280: crit.addIn(TurbineUserGroupRolePeer.GROUP_ID, groups);
281: crit.addJoin(ScarabUserImplPeer.USER_ID,
282: TurbineUserGroupRolePeer.USER_ID);
283:
284: crit
285: .add(ScarabUserImplPeer
286: .getColumnName(User.CONFIRM_VALUE),
287: (Object) ScarabUser.DELETED,
288: Criteria.NOT_EQUAL);
289:
290: try {
291: User[] users = TurbineSecurity.getUsers(crit);
292: result = new ScarabUser[users.length];
293: for (int i = result.length - 1; i >= 0; i--) {
294: result[i] = (ScarabUser) users[i];
295: }
296: } catch (Exception e) {
297: getLog()
298: .error(
299: "An exception prevented retrieving any users",
300: e);
301: // this method should probably throw the exception, but
302: // until the interface is changed, wrap it in a RuntimeExc.
303: throw new RuntimeException(
304: "Please check turbine.log for more info: "
305: + e.getMessage()); //EXCEPTION
306: }
307: } else {
308: result = new ScarabUser[0];
309: }
310: ScarabCache.put(result, this , GET_USERS,
311: (Serializable) permissions);
312: } else {
313: result = (ScarabUser[]) obj;
314: }
315: return result;
316: }
317:
318: /**
319: * @see org.tigris.scarab.om.Module#getUsers(String, String, String, String, IssueType)
320: * @param mitList MITs to restrict the user's search. If null, it will not be restricted.
321: */
322: public ScarabPaginatedList getUsers(final String name,
323: final String username, final MITList mitList,
324: final int pageNum, final int resultsPerPage,
325: final String sortColumn, final String sortPolarity,
326: final boolean includeCommitters) throws TorqueException,
327: DataSetException {
328: final int polarity = sortPolarity.equals("asc") ? 1 : -1;
329: List result = null;
330: ScarabPaginatedList paginated = null;
331:
332: final Comparator c = new Comparator() {
333: public int compare(Object o1, Object o2) {
334: int i = 0;
335: if ("username".equals(sortColumn)) {
336: i = polarity
337: * ((ScarabUser) o1).getUserName()
338: .compareTo(
339: ((ScarabUser) o2)
340: .getUserName());
341: } else {
342: i = polarity
343: * ((ScarabUser) o1).getName().compareTo(
344: ((ScarabUser) o2).getName());
345: }
346: return i;
347: }
348: };
349:
350: final Criteria crit = new Criteria();//
351: final Criteria critCount = new Criteria();
352: critCount.addSelectColumn("COUNT(DISTINCT "
353: + TurbineUserPeer.USERNAME + ")");
354: if (mitList != null) {
355: final List modules = mitList.getModules();
356: for (Iterator it = modules.iterator(); it.hasNext();) {
357: final Module mod = (Module) it.next();
358: final List perms = mitList
359: .getUserAttributePermissions();
360: if (includeCommitters
361: && !perms
362: .contains(org.tigris.scarab.services.security.ScarabSecurity.ISSUE__ENTER)) {
363: perms
364: .add(org.tigris.scarab.services.security.ScarabSecurity.ISSUE__ENTER);
365: }
366:
367: crit
368: .addIn(TurbinePermissionPeer.PERMISSION_NAME,
369: perms);
370: crit.setDistinct();
371: critCount.addIn(TurbinePermissionPeer.PERMISSION_NAME,
372: perms);
373: }
374: crit.addIn(TurbineUserGroupRolePeer.GROUP_ID, mitList
375: .getModuleIds());
376: critCount.addIn(TurbineUserGroupRolePeer.GROUP_ID, mitList
377: .getModuleIds());
378: }
379: crit.addJoin(TurbineUserPeer.USER_ID,
380: TurbineUserGroupRolePeer.USER_ID);
381: crit.addJoin(TurbineUserGroupRolePeer.ROLE_ID,
382: TurbineRolePermissionPeer.ROLE_ID);
383: crit.addJoin(TurbineRolePermissionPeer.PERMISSION_ID,
384: TurbinePermissionPeer.PERMISSION_ID);
385: critCount.addJoin(TurbineUserPeer.USER_ID,
386: TurbineUserGroupRolePeer.USER_ID);
387: critCount.addJoin(TurbineUserGroupRolePeer.ROLE_ID,
388: TurbineRolePermissionPeer.ROLE_ID);
389: critCount.addJoin(TurbineRolePermissionPeer.PERMISSION_ID,
390: TurbinePermissionPeer.PERMISSION_ID);
391:
392: if (name != null) {
393: int nameSeparator = name.indexOf(" ");
394: if (nameSeparator != -1) {
395: final String firstName = name.substring(0,
396: nameSeparator);
397: final String lastName = name.substring(
398: nameSeparator + 1, name.length());
399: crit.add(ScarabUserImplPeer.FIRST_NAME,
400: addWildcards(firstName), Criteria.LIKE);
401: crit.add(ScarabUserImplPeer.LAST_NAME,
402: addWildcards(lastName), Criteria.LIKE);
403: critCount.add(ScarabUserImplPeer.FIRST_NAME,
404: addWildcards(firstName), Criteria.LIKE);
405: critCount.add(ScarabUserImplPeer.LAST_NAME,
406: addWildcards(lastName), Criteria.LIKE);
407:
408: } else {
409: String[] tableAndColumn = StringUtils.split(
410: ScarabUserImplPeer.FIRST_NAME, ".");
411: final Criteria.Criterion fn = crit.getNewCriterion(
412: tableAndColumn[0], tableAndColumn[1],
413: addWildcards(name), Criteria.LIKE);
414: tableAndColumn = StringUtils.split(
415: ScarabUserImplPeer.LAST_NAME, ".");
416: final Criteria.Criterion ln = crit.getNewCriterion(
417: tableAndColumn[0], tableAndColumn[1],
418: addWildcards(name), Criteria.LIKE);
419: fn.or(ln);
420: crit.add(fn);
421: critCount.add(fn);
422: }
423: }
424:
425: if (username != null) {
426: crit.add(ScarabUserImplPeer.LOGIN_NAME,
427: addWildcards(username), Criteria.LIKE);
428: critCount.add(ScarabUserImplPeer.LOGIN_NAME,
429: addWildcards(username), Criteria.LIKE);
430: }
431:
432: String col = ScarabUserImplPeer.FIRST_NAME;
433: if (sortColumn.equals("username"))
434: col = ScarabUserImplPeer.USERNAME;
435: if (sortPolarity.equals("asc")) {
436: crit.addAscendingOrderByColumn(col);
437: } else {
438: crit.addDescendingOrderByColumn(col);
439: }
440:
441: final int totalResultSize = ScarabUserImplPeer
442: .getUsersCount(critCount);
443:
444: crit.setOffset((pageNum - 1) * resultsPerPage);
445: crit.setLimit(resultsPerPage);
446: result = ScarabUserImplPeer.doSelect(crit);
447:
448: // if there are results, sort the result set
449: if (totalResultSize > 0 && resultsPerPage > 0) {
450:
451: paginated = new ScarabPaginatedList(result,
452: totalResultSize, pageNum, resultsPerPage);
453: } else {
454: paginated = new ScarabPaginatedList();
455: }
456:
457: return paginated;
458: }
459:
460: /**
461: * @see org.tigris.scarab.om.Module#getUsers(String, String, String, String, IssueType)
462: * This implementation adds wildcard prefix and suffix and performs an SQL
463: * LIKE query for each of the String args that are not null.
464: * WARNING: This is potentially a very EXPENSIVE method.
465: */
466: public List getUsers(String firstName, String lastName,
467: String username, String email, IssueType issueType)
468: throws TorqueException {
469: List result = null;
470: // 4th element is ignored due to bug in torque
471: Serializable[] keys = { this , GET_USERS, firstName, null,
472: lastName, username, email, issueType };
473: Object obj = ScarabCache.get(keys);
474: if (obj == null) {
475: ScarabUser[] eligibleUsers = getUsers(getUserPermissions(issueType));
476: if (eligibleUsers == null || eligibleUsers.length == 0) {
477: result = Collections.EMPTY_LIST;
478: } else {
479: List userIds = new ArrayList();
480: for (int i = 0; i < eligibleUsers.length; i++) {
481: userIds.add(eligibleUsers[i].getUserId());
482: }
483: Criteria crit = new Criteria();
484: crit.addIn(ScarabUserImplPeer.USER_ID, userIds);
485:
486: if (firstName != null) {
487: crit.add(ScarabUserImplPeer.FIRST_NAME,
488: addWildcards(firstName), Criteria.LIKE);
489: }
490: if (lastName != null) {
491: crit.add(ScarabUserImplPeer.LAST_NAME,
492: addWildcards(lastName), Criteria.LIKE);
493: }
494: if (username != null) {
495: crit.add(ScarabUserImplPeer.LOGIN_NAME,
496: addWildcards(username), Criteria.LIKE);
497: }
498: if (email != null) {
499: crit.add(ScarabUserImplPeer.EMAIL,
500: addWildcards(email), Criteria.LIKE);
501: }
502: result = ScarabUserImplPeer.doSelect(crit);
503: }
504: ScarabCache.put(result, keys);
505: } else {
506: result = (List) obj;
507: }
508: return result;
509: }
510:
511: private Object addWildcards(String s) {
512: return new StringBuffer(s.length() + 2).append('%').append(s)
513: .append('%').toString();
514: }
515:
516: /**
517: * Wrapper method to perform the proper cast to the BaseModule method
518: * of the same name. FIXME: find a better way
519: */
520: public void setParent(Module v) throws TorqueException {
521: super .setModuleRelatedByParentId(v);
522: // setting the name to be null so that
523: // it gets rebuilt with the new information
524: setName(null);
525: resetAncestors();
526: }
527:
528: /**
529: * Cast the getScarabModuleRelatedByParentId() to a Module
530: */
531: public Module getParent() throws TorqueException {
532: return super .getModuleRelatedByParentId();
533: }
534:
535: /**
536: * Override method to make sure the module name gets recalculated.
537: *
538: * @param id a <code>Integer</code> value
539: */
540: public void setParentId(Integer id) throws TorqueException {
541: super .setParentId(id);
542: // setting the name to be null so that
543: // it gets rebuilt with the new information
544: setName(null);
545: resetAncestors();
546: }
547:
548: /**
549: * This method returns a complete list of RModuleIssueTypes
550: * which are not deleted, have a IssueType.PARENT_ID of 0 and
551: * sorted ascending by PREFERRED_ORDER.
552: */
553: public List getRModuleIssueTypes() throws TorqueException {
554: return super .getRModuleIssueTypes("preferredOrder", "asc");
555: }
556:
557: /**
558: * The number of active issues within the module.
559: *
560: * @param user a <code>ScarabUser</code> value used to determine if
561: * a count should be given.
562: * @return an <code>int</code> the number of issues entered for the
563: * module unless the user does not have permission to
564: * search for issues in the given module, then a value of 0 will be
565: * returned. if resource limited, this method will return -1.
566: * @throws DataSetException
567: * @exception Exception if an error occurs
568: */
569: public int getIssueCount(ScarabUser user,
570: AttributeOption attributeOption) throws TorqueException,
571: ScarabException, DataSetException {
572: Criteria crit = new Criteria();
573:
574: Integer attributeId = attributeOption.getAttributeId();
575: Integer optionId = attributeOption.getOptionId();
576:
577: crit.add(AttributeValuePeer.ATTRIBUTE_ID, attributeId);
578: crit.add(AttributeValuePeer.OPTION_ID, optionId);
579: crit.add(IssuePeer.MODULE_ID, getModuleId());
580: crit.add(IssuePeer.MOVED, 0);
581: crit.add(IssuePeer.DELETED, 0);
582: crit.add(IssuePeer.ID_COUNT, 0, SqlEnum.GREATER_THAN);
583: crit.addJoin(AttributeValuePeer.ISSUE_ID, IssuePeer.ISSUE_ID);
584: crit.add(AttributeValuePeer.DELETED, 0);
585: int count = AttributeValuePeer.count(crit);
586: return count;
587: }
588:
589: /**
590: * The number of active issues within the module.
591: *
592: * @param user a <code>ScarabUser</code> value used to determine if
593: * a count should be given.
594: * @return an <code>int</code> the number of issues entered for the
595: * module unless the user does not have permission to
596: * search for issues in the given module, then a value of 0 will be
597: * returned. if resource limited, this method will return -1.
598: * @throws DataSetException
599: * @exception Exception if an error occurs
600: */
601: public int getIssueCount(ScarabUser user) throws TorqueException,
602: ScarabException, DataSetException {
603: Criteria crit = new Criteria();
604: crit.add(IssuePeer.MODULE_ID, getModuleId());
605: crit.add(IssuePeer.DELETED, 0);
606: crit.add(IssuePeer.MOVED, 0);
607: crit.add(IssuePeer.ID_COUNT, 0, SqlEnum.GREATER_THAN);
608: int count = IssuePeer.count(crit);
609: return count;
610: }
611:
612: /**
613: * Returns RModuleAttributes associated with this Module. Tries to find
614: * RModuleAttributes associated directly through the db, but if none are
615: * found it should look up the parent module tree until it finds a
616: * non-empty list.
617: */
618: public List getRModuleAttributes(Criteria crit)
619: throws TorqueException {
620: return super .getRModuleAttributes(crit);
621: }
622:
623: /**
624: * Returns associated RModuleOptions. if a related AttributeOption is
625: * deleted the RModuleOption will not show up in this list.
626: *
627: * @param crit a <code>Criteria</code> value
628: * @return a <code>List</code> value
629: */
630: public List getRModuleOptions(Criteria crit) throws TorqueException {
631: crit.addJoin(RModuleOptionPeer.OPTION_ID,
632: AttributeOptionPeer.OPTION_ID).add(
633: AttributeOptionPeer.DELETED, false);
634: return super .getRModuleOptions(crit);
635: }
636:
637: public boolean allowsIssues() {
638: return (true);
639: }
640:
641: /**
642: * Saves the module into the database
643: * @throws ScarabRuntimeException when a TorqueException is thrown internally.
644: */
645: public void save() {
646: try {
647:
648: super .save();
649: } catch (TorqueException e) {
650: // a way to satisfy method signature regarding "throws" for Torque class and Group class.
651: // that is hide it all by throwing a RuntimeException.
652: // usuages of this method must be careful of this!
653: throw new ScarabRuntimeException(new L10NKey(
654: "ScarabModule.save TorqueException <localize me>"),
655: e); //EXCEPTION
656: }
657: }
658:
659: /**
660: * Saves the module into the database. Note that this
661: * cannot be used within a activitySet if the module isNew()
662: * because dbCon.commit() is called within the method. An
663: * update can be done within a activitySet though.
664: */
665: public void save(final Connection dbCon) throws TorqueException {
666: // if new, make sure the code has a value.
667: if (isNew()) {
668: final Criteria crit = new Criteria();
669: crit.add(ScarabModulePeer.MODULE_NAME, getRealName());
670: crit.add(ScarabModulePeer.PARENT_ID, getParentId());
671: // FIXME: this should be done with a method in Module
672: // that takes the two criteria values as a argument so that other
673: // implementations can benefit from being able to get the
674: // list of modules. -- do not agree - jdm
675:
676: List result;
677: try {
678: result = ScarabModulePeer.doSelect(crit);
679: } catch (TorqueException te) {
680: throw new ScarabLocalizedTorqueException(
681: new ScarabException(
682: L10NKeySet.ExceptionTorqueGeneric, te));
683: }
684:
685: if (result.size() > 0) {
686: throw new ScarabLocalizedTorqueException(
687: new ScarabException(
688: L10NKeySet.ExceptionModuleAllreadyExists,
689: getRealName(), getParentId()));
690: }
691:
692: final String code = getCode();
693: if (code == null || code.length() == 0) {
694: if (getParentId().equals(ROOT_ID)) {
695: throw new ScarabLocalizedTorqueException(
696: new ScarabException(
697: L10NKeySet.ExceptionTopLevelModuleWithoutCode));
698: }
699:
700: try {
701: setCode(getParent().getCode());
702: } catch (Exception e) {
703: throw new ScarabLocalizedTorqueException(
704: new ScarabException(
705: L10NKeySet.ExceptionCantPropagateModuleCode,
706: e));
707: }
708: }
709:
710: // need to do this before the relationship save below
711: // in order to set the moduleid for the new module.
712: super .save(dbCon);
713: try {
714: dbCon.commit();
715: } catch (Exception e) {
716: throw new ScarabLocalizedTorqueException(
717: new ScarabException(
718: L10NKeySet.ExceptionGeneric, e));
719: }
720:
721: if (getOwnerId() == null) {
722: throw new ScarabLocalizedTorqueException(
723: new ScarabException(
724: L10NKeySet.ExceptionSaveNeedsOwner));
725: }
726: // grant the ower of the module the Project Owner role
727: try {
728: final User user = ScarabUserManager
729: .getInstance(getOwnerId());
730:
731: final Role role = TurbineSecurity
732: .getRole(PROJECT_OWNER_ROLE);
733: grant(user, role);
734: setInitialAttributesAndIssueTypes();
735: } catch (Exception e) {
736: throw new ScarabLocalizedTorqueException(
737: new ScarabException(
738: L10NKeySet.ExceptionGeneric, e));
739: }
740: } else {
741: super .save(dbCon);
742: }
743:
744: // clear out the cache beause we want to make sure that
745: // things get updated properly.
746: ScarabCache.clear();
747: }
748:
749: // *******************************************************************
750: // Turbine Group implementation get/setName and save are defined in
751: // parent class AbstractScarabModule
752: // *******************************************************************
753:
754: /**
755: * Removes a group from the system.
756: *
757: * @throws TurbineSecurityException if the Group could not be removed.
758: */
759: public void remove() throws TurbineSecurityException {
760: throw new TurbineSecurityException("Not implemented"); //EXCEPTION
761: }
762:
763: /**
764: * Renames the group.
765: *
766: * @param name The new Group name.
767: * @throws TurbineSecurityException if the Group could not be renamed.
768: */
769: public void rename(String name) throws TurbineSecurityException {
770: throw new TurbineSecurityException("Not implemented"); //EXCEPTION
771: }
772:
773: /**
774: * Grants a Role in this Group to an User.
775: *
776: * @param user An User.
777: * @param role A Role.
778: * @throws TurbineSecurityException if there is a problem while assigning
779: * the Role.
780: */
781: public void grant(User user, Role role)
782: throws TurbineSecurityException {
783: TurbineSecurity.grant(user, this , role);
784:
785: // TODO: Needs to be refactored into the Users system?
786: ScarabUserManager.getMethodResult().remove(user.getUserName(),
787: ScarabUserManager.GET_ACL);
788: ScarabUserManager.getMethodResult().remove(user.getUserName(),
789: ScarabUserManager.HAS_ROLE_IN_MODULE, role.getName(),
790: this .getModuleId());
791: }
792:
793: /**
794: * Grants Roles in this Group to an User.
795: *
796: * @param user An User.
797: * @param roleSet A RoleSet.
798: * @throws TurbineSecurityException if there is a problem while assigning
799: * the Roles.
800: */
801: public void grant(User user, RoleSet roleSet)
802: throws TurbineSecurityException {
803: throw new TurbineSecurityException("Not implemented"); //EXCEPTION
804: }
805:
806: /**
807: * Revokes a Role in this Group from an User.
808: *
809: * @param user An User.
810: * @param role A Role.
811: * @throws TurbineSecurityException if there is a problem while unassigning
812: * the Role.
813: */
814: public void revoke(User user, Role role)
815: throws TurbineSecurityException {
816: throw new TurbineSecurityException("Not implemented"); //EXCEPTION
817: }
818:
819: /**
820: * Revokes Roles in this group from an User.
821: *
822: * @param user An User.
823: * @param roleSet a RoleSet.
824: * @throws TurbineSecurityException if there is a problem while unassigning
825: * the Roles.
826: */
827: public void revoke(User user, RoleSet roleSet)
828: throws TurbineSecurityException {
829: throw new TurbineSecurityException("Not implemented"); //EXCEPTION
830: }
831:
832: /**
833: * Used for ordering Groups.
834: *
835: * @param obj The Object to compare to.
836: * @return -1 if the name of the other object is lexically greater than
837: * this group, 1 if it is lexically lesser, 0 if they are equal.
838: */
839: public int compareTo(Object obj) {
840: //---------------------------------------------------------------------
841: // dr@bitonic.com : commented out as per conversation with John McNally
842: // over IRC on 20-Dec-2001
843: //---------------------------------------------------------------------
844: //if (this.getClass() != obj.getClass())
845: //{
846: // throw new ClassCastException();
847: //}
848: String name1 = ((Group) obj).getName();
849: String name2 = this .getName();
850:
851: return name2.compareTo(name1);
852: }
853:
854: /**
855: * All emails related to this module will have a copy sent to
856: * this address. A system-wide default email address can be specified in
857: * Scarab.properties with the key: scarab.email.archive.toAddress
858: */
859: public String getArchiveEmail() {
860: String email = super .getArchiveEmail();
861: if (email == null || email.length() == 0) {
862: email = Turbine.getConfiguration().getString(
863: ScarabConstants.ARCHIVE_EMAIL_ADDRESS, null);
864: }
865:
866: return email;
867: }
868:
869: /**
870: * returns an array of Roles that can be approved without need for
871: * moderation.
872: */
873: public String[] getAutoApprovedRoles() {
874: return Turbine.getConfiguration().getStringArray(
875: ScarabConstants.AUTO_APPROVED_ROLES);
876: }
877:
878: /**
879: * Provides the flag, wether issue store needs valid reason.
880: * Note: This method returns true, when the global variable
881: * was not defined neither for this module nor for its ancestors.
882: * This may be the case when you migrate from an
883: * older version of scarab to a20++ where this parameter was not
884: * used. Thus per default Scarab makes the field required.
885: *
886: * @return true: yes, valid reason field needed; false: reason field may stay empty.
887: */
888: public boolean isIssueReasonRequired() {
889: String key = GlobalParameter.ISSUE_REASON_REQUIRED;
890: boolean result = GlobalParameterManager
891: .getBooleanFromHierarchy(key, this , true);
892: return result;
893: }
894:
895: /**
896: * Determines if the value of isIssueReasonRequired is due to the configuration
897: * of this module or inherited from ancestors or default configuration. The Global module
898: * does never inherite the value, that's by default 'True'.
899: * @return True if the configuration is inherited.
900: */
901: public boolean isIssueReasonRequiredInherited() {
902: if (this .isGlobalModule())
903: return false;
904:
905: String val = null;
906: try {
907: val = GlobalParameterManager.getString(
908: GlobalParameter.ISSUE_REASON_REQUIRED, this );
909: } catch (TorqueException te) {
910: getLog().error("isIssueReasonRequiredInherited(): " + te);
911: }
912: return (val == null || val.length() == 0);
913: }
914:
915: /**
916: * Checks if an attempt to register a role for this module
917: * needs a specific role. returns false, if no role is
918: * needed. otherwise return true.
919: * To get the needed role, @see #getRequiredRole()
920: * @return
921: */
922: public boolean registerNeedsRequiredRole() {
923: Role role = getRequiredRole();
924: boolean result = (role != null);
925: return result;
926: }
927:
928: /**
929: * Returns the required role for *any* access to this module
930: * including for requesting roles.
931: * @return
932: */
933: public Role getRequiredRole() {
934: String key = GlobalParameter.REQUIRED_ROLE_FOR_REQUESTING_ACCESS;
935: Role result = null;
936: try {
937: String val = GlobalParameterManager.getString(key, this );
938: if (val != null && val.length() > 0)
939: result = TurbineSecurity.getRole(val);
940: } catch (Exception e) {
941: getLog().error("getRequiredRole(): " + e);
942: }
943: return result;
944: }
945:
946: /**
947: * Returns the comment rendering engine currently in use.
948: * @return
949: */
950: public String getCommentRenderingEngine() {
951: // TODO: We should return a RenderEngine here and hide
952: // all rendering details in the returned instance.
953: // currently we provide radeoz and plaintext only.
954: // this may change soon ;-) [HD]
955: //
956: String key = GlobalParameter.COMMENT_RENDER_ENGINE;
957: String result = null;
958: try {
959: result = GlobalParameterManager.getString(key, this );
960: } catch (Exception e) {
961: getLog().error("getCommentRenderingEngine(): " + e);
962: }
963:
964: if (result == null || result.equals("")) {
965: result = ScarabConstants.COMMENT_RENDER_ENGINE;
966: }
967: return result;
968: }
969:
970: /**
971: * Gets all module roles.
972: */
973: public List getRoles() throws TorqueException {
974: return new ArrayList(0);
975: }
976:
977: public String toString() {
978: return '{' + super .toString() + " - ID=" + getModuleId()
979: + " - " + getName() + '}';
980: }
981: }
|